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 | }
|