ATmega 16 AVRGCC SRF02 Distanzmessung

#3154411
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
#3154484
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.
#3154519
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren