(price for 10 pcs of Chip and Dip store at the time of publication)
I could never resist buying various electronic pieces, and once I had 10
very small MK more. I love ATtiny13 - cheap and cheerful. When I bought them, I firmly remembered that they had
“Even an ADC, not like a timer!”, And I was very happy about their low price.
However, when I confronted ATtiny13 with a real task, it turned out that there was no one very important thing in it, namely,
interfaces for data transmission (of course, not counting GPIO).
Well, if there is a GPIO, then you can write anything! I thought and went to google ... And I didn’t googled a beautiful ready-made solution for avr-gcc ... I’m looking for a (hopefully) such solution, this article is welcome under cat.
In fact, there were about three options, but in
one they write in BASIC (I didn’t even know what I could do), in the
other one under CVAVR (hello to my first blinking LED) and in general there is a whole semantic code in a terrible assembler, but the
third one It seems to be suitable ... But some very strange code ... But it earned a spolpink. But zhiirny ...
Program Memory Usage: 508 bytes 49.6% Full
Well, okay, the main thing is working and holding, and there it is already possible to both read and refactor ... JumpStart took place - this is the main thing.
After a thoughtful reading of the code, it becomes clear that its author deserves deep respect ... This code is similar to the code of a person who is programming VERY recently, and the task is solved quite powerful. It works the same. I really wanted for beginners to describe a few trivial errors, but after the third one I realized that it was very offtopic, so, alas ...
')
In the original , the code was engaged in receiving and sending data, but in reality, my task does not require reception (especially in the main loop). It's enough for me to just catch Pin Change Interrupt on any leg and spit out the results of A-> D conversion. According to this, in order to lose weight, it was decided to cut a technique. This is what happened after not very long and not very thoughtful refactoring:
#define F_CPU 9600000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> uint8_t temp, count, start; volatile uint8_t c; #define BAUD_C 123 #define TxD PB4 #define T_START TCCR0B = (1 << CS01) // F_CPU/8 #define T_STOP TCCR0B = 0 #define T_RESET TCNT0 = 0 ISR(TIM0_COMPA_vect){ OCR0A = BAUD_C; c = 1; T_RESET; } void send(uint8_t data) { // "lov"? 0_ if (count >= 8) { PORTB |= (1<<TxD); start = 0; temp = 0; c = 0; count = 0; T_STOP; OCR0A = 0; return; } if(c == 1) { if (start == 0) { temp = 0x80; start = 1; count--; } else { temp = data; temp = temp >> count; temp = temp << 7; } switch(temp) { case 0x80 : PORTB &= ~(1 << TxD); break; case 0 : PORTB |= (1 << TxD); break; } count++; c = 0; } } void send_ch(uint8_t data){ uint8_t f; data = ~data; T_START; for(f = 0; f < 10; f++){ while(c == 0); send(data); } }
I do not want to think much, so I left the whole semantic part as it is, threw out the superfluous and corrected vyrvlazlaznye things like
TIMSK0 = 0x04 . I really liked the spacing implementation in this code! All hemorrhoids with the calculation of constants for baud rate are reduced to one number BAUD_C, which is chosen almost experimentally and corrected depending on the inaccuracies of quartz (the author had it equal to 115 and seemed to work quite accurately on the screenshot. Is it possible at all such a hard floating? ). Most likely, this is not the most optimal, reliable and correct
bla bla bla bla solution, but it seems to me very simple and beautiful!
Well, what is the result?
Program Memory Usage: 304 bytes 29.7% Full
“Fuh, we live. There is also enough on the ADC ... ” But in general, this is not the end. Now the code is able to transfer only one character, but it is necessary to transfer lines and values ​​of registers. So, time to rummage in old projects! This task is no longer specific for MK without UART and has been solved repeatedly.
void send_str(char *text){ while(*text) { send_ch(*text++); } } void itoa(uint16_t n, char s[]) { uint8_t i = 0; do { s[i++] = n % 10 + '0'; } while ((n /= 10) > 0); s[i] = '\0';
It is very convenient to send numbers at once with explanations of what these numbers are, therefore
send_num (char * text, uint16_t n) .
And, taking into account the example of use:
int main(void){ DDRB |= (1 << TxD); TIMSK0 = (1 << OCIE0A); sei(); while(1){ _delay_ms(1); send_num("Habr:", 4242); } }
Turns out
Program Memory Usage: 538 bytes 52.5% Full
Slightly more than the original. But how much more useful!
I want to immediately warn you that the goal to make a beautiful and popular article was not. It was written very quickly, it was re-read very little and may contain very errors. Please do not troll - I'll fix everything. The main thing is that this problem ceases to exist and everyone who wants to build their sensor on ATtiny13 should have a ready solution for the interface.
PS: At first I looked at I2C and even
found a very promising repository, but did not understand why Atmel Studio says overflow. It would be cool to write down this interface on t13 - it might even get worse ... But this is not me.
PSS:
My logic analyzer . He is gorgeous!