Forum: Compiler & IDEs ATmega 16 AVRGCC SRF02 Distanzmessung


von Achmed B. (xeno1987)


Lesenswert?

Liebe Gemeinde,

Ich komme gerade nicht weiter. Wenn ich vom ADC Wandler den Wert become 
der dann zwischen 0-1023 liegt und dann in cm umgerechnet warden soll 
und zwar für 15cm bis 50cm. Kann ich da einfach als Formel das 
proportional nehmen oder muss ich da noch was beachten?

Hier mein bisheriger Code(bzw. der mir zur Verfügung gestellte)

•
1
#include <util/twi.h>
2
3
4
5
////////////////////////////////////////////////////////////
6
// Interne-Routinen:
7
////////////////////////////////////////////////////////////
8
9
/*   Gibt 1 zurück, falls TWINT gesetzt wird.
10
  Falls nach 40000 Schleifendurchgängen TWINT
11
  noch nicht gesetzt wurde, gibt 0 zurück.
12
  */  
13
int twi_wait4TWINT() {
14
  uint16_t x=0;
15
  while (x < 40000) { 
16
    x++; 
17
    if ( TWCR & (1<<TWINT) ) {  return 1; }    
18
  }
19
  return 0;
20
}
21
22
/*  Gibt 0 zurück, falls der Parameter status nicht
23
  in den oberen 5 Bytes von TWSR zu finden ist. 
24
  Sonst, wenn alles in Ordnung ist 1. 
25
  */
26
int twi_check( uint8_t status ) {
27
  return ((TWSR & 0xF8) == status );
28
}
29
30
31
////////////////////////////////////////////////////////////
32
// Init-, Start- und Stop-Routinen:
33
////////////////////////////////////////////////////////////
34
35
/*   Setzt die Geschwindikeit des Busses abhängig von der 
36
  CPU-Geschwindigkeit. */
37
void twi_init() {
38
39
  TWBR = 2;
40
  TWSR = 0;
41
  //==> SLCfreq==50KHz bei 1MHz CPU-Takt
42
}
43
44
45
/*  Leitet einen TWI (I2C) Sende- oder Empfangsvorgang ein.
46
  Falls erfolgreich, gibt 1 zurück sonst 0; */
47
int twi_start() {
48
49
  // Setze Start-Condition:
50
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
51
52
  // Warte auf das TWINT-Flag:
53
  //twi_wait4TWINT();
54
  
55
  while(!(TWCR & (1 << TWINT))) ;
56
57
  // Gebe den Status zurück:
58
  return ((TWSR & 0xF8) == TW_START);
59
}
60
61
62
int twi_rep_start(){
63
  // Setze Start-Condition:
64
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
65
66
  // Warte: auf das TWINT-Flag:
67
  twi_wait4TWINT();
68
69
  // Gebe den Status zurück:
70
  return twi_check(TW_REP_START);
71
}
72
73
74
/*  Beendet einen TWI (I2C) Sende- oder Empfangsvorgang. */
75
void twi_stop(){
76
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
77
}
78
79
80
////////////////////////////////////////////////////////////
81
// Sende-Routinen:
82
////////////////////////////////////////////////////////////
83
84
int twi_sla_w(uint8_t slave_adress){
85
86
  TWDR = slave_adress;          // Slave Adresse in das Data Register schreiben
87
  TWCR = (1<<TWINT) | (1<<TWEN);      // Adresse senden.
88
89
  // Warten auf das TWINT-Flag
90
  twi_wait4TWINT();
91
92
93
  return twi_check(TW_MT_SLA_ACK);
94
}
95
96
int twi_sla_r(uint8_t slave_adress){
97
98
  TWDR = slave_adress;          // Slave Adresse in das Data Register schreiben
99
  TWCR = (1<<TWINT)|(1<<TWEN);      // Adresse senden.
100
101
  // Warten auf das TWINT-Flag
102
  twi_wait4TWINT();
103
104
  return twi_check(TW_MR_SLA_ACK);
105
}
106
107
int twi_send(uint8_t data){
108
109
  TWDR = data;              // Datum in das Data Register schreiben
110
  TWCR = (1<<TWINT)|(1<<TWEN);      // Datum Senden.
111
112
  // Warten auf das TWINT-Flag
113
  twi_wait4TWINT();
114
115
  return twi_check(TW_MT_DATA_ACK);
116
}
117
118
119
////////////////////////////////////////////////////////////
120
// Empfangs-Routine:
121
////////////////////////////////////////////////////////////
122
123
/*  Liest ein Byte vom Bus. 
124
125
  Parameter:
126
  int ack     - ACK-Bit
127
  uint8_t* data  - Unter *data wird das gelesene Byte gespeichert
128
129
  Falls ack!=0 wird der Empfang mit einem  ACK-Bit bestätigt 
130
  (== Erwarte nächstes Byte). Sonst wird das Bit nicht gesetzt 
131
  (== Transmission beendet).
132
133
  Rückgabewert:
134
  Die Methode gibt eine 0 zurück falls ein Fehler auftritt. Sonst eine 1.
135
  Ein Fehler tritt auf wenn:
136
    - data==0 (null-pointer)
137
    - Lesen nicht erfolgreich war.
138
139
  Falls das Lesen nicht erfolgreich war, wird *data auf 0x00 gesetzt.
140
  
141
*/
142
int twi_read(int ack, uint8_t* data){
143
144
  // Falls data ein 0-Pointer ist, beende:
145
  if (data==0) { return 0; }
146
147
  // Starte den Lesevorgang:
148
  if (ack) {                // ACK Senden
149
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
150
  } else {                // NACK Senden
151
    TWCR = (1<<TWINT)|(1<<TWEN);
152
  }
153
154
  // Warten auf das TWINT-Flag
155
  twi_wait4TWINT();
156
157
  // Überprüfe den Status des Lesevorgangs:
158
  int status = 0;
159
  if (ack) {   
160
    status = twi_check(TW_MR_DATA_ACK); 
161
  } else {
162
    status = twi_check(TW_MR_DATA_NACK);
163
  }
164
165
  // Falls lesen erfolgreich, übergebe es an die
166
  // *data-Variable. Sonst setze *data auf 0:
167
  if (status) {
168
    // Lese das Datenregister:
169
    *data = TWDR;
170
  } else {
171
    *data = 0;
172
  }
173
174
175
  // gebe den Status zurück:
176
  return status;
177
178
}
1
#include <stdlib.h>
2
#include <avr/io.h>
3
#include <stdio.h>
4
#ifndef F_CPU
5
#    define F_CPU 1000000UL
6
#endif
7
#include <util/delay.h>
8
#include <util/twi.h>
9
10
#include "iti_twi.h"
11
#include "uart.h"
12
13
extern void check3();
14
uint16_t adc_get();
15
16
// Please, DO NOT change anything above this line
17
18
/**************************************************************************************************
19
 * TODO:
20
 *
21
 * Try to to carry out step-by-step the following tasks. At the end of each
22
 * task compile, flash and run the code to check whether it works.
23
 *
24
 * 1. Program the port B as digital output completing the functions led_init() and led_display()
25
 *   Set CHECK to 1, and test the code!
26
 *
27
 * 2. Now perform an ADC conversion writing the code in the functions adc_init() and adc_get()
28
 *   Set CHECK to 2, and test the code!
29
 * 
30
 * 3. Get familiar with the I2C bus, writing the code to read and write a register on an external
31
      device; complete the functions twi_writeregister(...) and twi_readregister(...)
32
 *   Set CHECK to 3, and test the code!
33
 * 
34
 * 4. Finally, put all together!
35
 *      Set CHECK to 0. Then, scroll down to the marked position and write a C-code that 
36
 *      performs the following operations. Then compile, flash and see everything working...hopefully!
37
 *
38
 *      a. initialize all the require peripherals (LEDs, ADC, TWI)
39
 *   while(1) {
40
 *    b. read the ADC connected to the potentiometer
41
 *       c. display its raw value on the led bar
42
 *     d. write a formula to convert this value from the range 0..1023 into the range 15..50
43
 *      e. use the last converted value (in the range 15..50) as obstacle collision threshold:
44
 *         - below this value the LEDs on the display start blinking alerting 
45
 *           about the presence of a very close object!
46
 *         (to make the led blinking, shut them off for 150 ms, then on again)
47
 *         - use printf to display the actual distance on the monitor
48
 *   }
49
 *
50
 * HINT: printf can help you while debugging your code
51
 *
52
 **************************************************************************************************/
53
54
55
// Set the next constant to check your code. Then compile, flash and see what happens...
56
57
#define CHECK   0
58
59
//-------------------------------------------------------------------------------------------------
60
61
62
/**
63
 * This function initializes the PORTB as digital output.
64
 * Port B is connected directly to the LEDs bar.
65
 * All the 8-bits are required as output.
66
 * 
67
 * 
68
 * Paramter:
69
 *   -
70
 * 
71
 * Return:
72
 *   -
73
 */
74
void led_init() {
75
  // TODO: Configure port B as digital output
76
  DDRB = 0xFF;
77
  
78
}
79
80
/**
81
 * This function sets the PORTB in order to drive the led bar. The number
82
 * of contiguous led to switch on is proportional to the value passed as paramter. 
83
 * Such value has to be in the range 0-1023. All the leds are off only 
84
 * when the input value == 0, while any other value will turn on a number 
85
 * of leds proportional to the value itself. For example, if the value is 123
86
 * the led bar display the led0 on. If it is 300, led0 and led1 are on. 
87
 * And so on...
88
 * 
89
 * Paramter:
90
 *   - uint16_t value, the number in the range 0-1023 to display on the led bar
91
 * 
92
 * Return:
93
 *   -
94
 */
95
void led_display(uint16_t value) {
96
  // TODO:
97
  // 1. If the input value is 0, set port B to 0.
98
  // 2. Otherwise, set to digital one a contiguos number of bit -in the port B-
99
  //    proportional to the input value.
100
  if(value == 0) PORTB = 0x00;
101
102
  else if((value <= 127) && (value > 0)) PORTB = (1<<PB0);
103
  
104
  else if((value <= 255) && (value > 127)) PORTB = (1<<PB0) | (1<<PB1);
105
  
106
  else if((value <= 383) && (value > 255)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2);
107
  
108
  else if((value <= 511) && (value > 383)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3);
109
  
110
  else if((value <= 639) && (value > 511)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4);
111
  
112
  else if((value <= 767) && (value > 639)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5);
113
  
114
  else if((value <= 895) && (value > 767)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5) | (1<<PB6);    
115
116
  else if((value <= 1023) && (value > 895)) PORTB = (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3) | (1<<PB4) | (1<<PB5) | (1<<PB6) | (1<<PB7);    
117
118
}
119
120
121
/**
122
 * Initialize the ADC.
123
 * 
124
 * Params:
125
 *  - 
126
 * 
127
 * Return:
128
 *  -
129
 */
130
void adc_init() {
131
  // TODO:
132
  // 1. Enable the ADC by setting the bit ADEN in the register ADCSRA, 
133
  //    and configure the prescaler with a  division factor of 128
134
  //    selecting ADPS2:0 as mentioned in the Atmega16 datasheet.
135
  
136
  ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2);
137
138
  
139
  // 2. Set REFS1:0 in the ADMUX register to select the supply voltage 
140
  //    (VCC) as reference voltage (AVCC) for the ADC: set REFS1:0 to 01
141
142
  ADMUX = (1<<REFS0) | (0<<REFS1);
143
144
  // 3. Perform a dummy reading to clear the ADC before the first real
145
  //    reading, and ignore the result.
146
147
  adc_get();
148
}
149
150
/**
151
 * Get a value from the ADC.
152
 * 
153
 * Params:
154
 *  - 
155
 * 
156
 * Return:
157
 *  - the raw value read on the ADC.
158
 */
159
uint16_t adc_get() {
160
  // TODO:
161
  // 1. Set the bit ADSC to start a conversion, but be careful not to 
162
  //    alter other bits set before during the initialization!
163
164
  ADCSRA = (1<<ADSC);
165
  
166
  // 2. Wait until the ADSC bit is cleared up again: that means the
167
  //    conversion is done.
168
169
  while(ADSC != 0);
170
  
171
  // 3. Return the value you can read in the register ADCW.
172
173
  return ADCW;
174
}
175
176
/**
177
 * Write a byte in a specific register of a TWI device.
178
 *
179
 *  Params: 
180
 *  uint8_t twi_addr,   the addresse of the TWI device to communicate with
181
 *  uint8_t reg,    the number of the register in the TWI device to write to
182
 *  uint8_t data,    data byte to be written
183
 *
184
 *  Return:
185
 *  - the status of the sending operation 
186
*/
187
uint8_t twi_writeregister(uint8_t twi_addr, uint8_t reg, uint8_t data) {
188
189
  uint8_t ret = 0;
190
191
  //TODO:
192
  // 1. Start the TWI communication, waiting until started
193
194
  twi_start();
195
196
  // 2. Write the address of the TWI device to communicate with
197
198
  twi_sla_w(twi_addr);
199
200
  // 3. Send the number of the register in the TWI device to write to
201
  
202
  twi_sla_r(reg);
203
204
  // 4. Send the data byte, saving the status of the operation in the variable ret
205
206
  twi_send(data);
207
  reg = twi_wait4TWINT();
208
209
  // 5. Stop the TWI communication, then return
210
211
  twi_stop();
212
213
  return ret;
214
}
215
216
/**
217
 * Read a byte from a specific register of a TWI device.
218
 *
219
 *  Params: 
220
 *  uint8_t twi_addr,   the addresse of the TWI device to communicate with
221
 *  uint8_t reg,    the number of the register in the TWI device to read from
222
 *  uint8_t *data,    pointer to a variable the incoming data is written to
223
 *
224
 *  Return:
225
 *  - the status of the reading operation 
226
*/
227
uint8_t twi_readregister(uint8_t twi_addr, uint8_t reg, uint8_t* data) {
228
229
  uint8_t ret = 0;
230
231
  //TODO:
232
  // 1. Start the TWI communication, waiting until started
233
234
  twi_start();
235
236
  // 2. Write the address of the TWI device to communicate with
237
238
  twi_sla_w(twi_addr);
239
240
  // 3. Send the number of the register in the TWI device to read from
241
242
  twi_sla_r(reg);
243
244
  // 4. Stop the communication
245
246
  twi_stop();
247
248
  // 5. Restart the TWI communication as before
249
250
  twi_rep_start();
251
252
  // 6. Put the read-address of the TWI device on the bus, remembering to set its LSB to 1
253
254
  twi_addr |= 0x01;  // setzen des untersten bits
255
  twi_sla_w(twi_addr);
256
257
  // 7. Read the byte from the bus into the pointed variable data. Perform the reading without ACK!
258
  //    Store in the variable ret the status of the reading operation.
259
260
  twi_read(0,data);
261
  ret = twi_wait4TWINT();
262
263
  // 8. Stop the TWI communication, then return
264
  
265
  twi_stop();
266
  
267
  return ret;
268
}
269
270
271
272
int main ( void ) {
273
// Please, DO NOT edit the next 26 lines, or the CHECK will not work properly
274
uart_init();
275
#if CHECK == 1
276
    uint16_t val = 0;
277
    led_init();
278
    while(1) {
279
      led_display(val);
280
      val++;
281
      val &= 0x3FF;
282
      _delay_ms(1);
283
    }
284
#elif CHECK == 2
285
    uint16_t raw;
286
    led_init();
287
    adc_init();
288
    while(1) {
289
      raw = adc_get();
290
      led_display(raw);
291
      _delay_ms(80);
292
    }
293
#elif CHECK == 3
294
    led_init();
295
    twi_init();
296
    while(1) {
297
      check3();
298
    }
299
#else
300
// ********************************************************************
301
// Put the code for the last task (4.) here:
302
303
uint16_t adcValue = 0;
304
305
// Initializing LED, ADC, TWI
306
307
  led_init();
308
  adc_init();
309
  twi_init();
310
311
  while(1){
312
313
    adcValue = adc_get();
314
    led_display(adcValue);
315
316
317
  }
318
319
320
// ********************************************************************
321
#endif
322
  return 0;
323
}
vg

von Karl H. (kbuchegg)


Lesenswert?

Achmed Binto schrieb:
> Liebe Gemeinde,
>
> Ich komme gerade nicht weiter. Wenn ich vom ADC Wandler den Wert become
> der dann zwischen 0-1023 liegt und dann in cm umgerechnet warden soll
> und zwar für 15cm bis 50cm. Kann ich da einfach als Formel das
> proportional nehmen

Das kommt drauf an, was der ADC Wert physikalisch repräsentiert.
Das Datenblatt des Sensors müsste dir doch eigentlich darüber Auskunft 
geben, was die Spannung darstellt und wie sie in eine Entfernung 
umzurechnen ist.

von Achmed B. (xeno1987)


Lesenswert?

hi,

im datenblatt steht dazu leider nichts drin. Nur dass man per command 
register wahl die einheiten festlegen kann, aber ich soll ja ne 
umrechnung machen.

von Stefan E. (sternst)


Lesenswert?

Achmed Binto schrieb:
> Wenn ich vom ADC Wandler den Wert become
> der dann zwischen 0-1023 liegt und dann in cm umgerechnet warden soll

Seit wann hat denn ein SRF02 überhaupt irgendeinen Analogausgang?

von Achmed B. (xeno1987)


Lesenswert?

hi,

ich hatte mich falsch ausgedrückt, der cm wert von dem sensor ist schon 
richtig, es ging hier um die umrechnung des gelesenen wertes vom 
potentiometer.

Aufgabenstellung:

Im fertigen System misst der ATmega16 eine durch einen einstellbaren 
Spannungsteiler erzeugte Analoge Spannung und stellt den gemessen Wert 
auf einer LED Leiste dar, wobei die Zahl der leuchtenden Dioden 
proportional zum eingestellten Spannungswert sein soll. Dieser 
Spannungswert wird dann in einem Abstand zwischen 15 und 50 cm 
umgerechnet der als Schwellwert für die Abstandsmessung dient. Wenn ein 
Objekt näher an den Abstandssensor heran kommt als durch diesen 
Schwellwert definiert, so soll die LED Leiste zu blinken beginnen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.