Hallo an alle Benutzer von Geektimes! Als Ergebnis meines Dienstes musste ich einmal die Software UART auf dem beliebten ATtiny13-Mikrocontroller implementieren. Beim Googeln habe ich eine große Anzahl von Artikeln zu diesem Thema gefunden, von denen viele hier veröffentlicht sind:Und es gibt noch andere Ressourcen:, -, ( ). , -, CodeVision AVR, , -, . C UART-. , ( 8- ). , .. , AVR.
— , , .
Also fangen wir an. Ich werde einfach die Header-Datei "uart13.h" in der Form veröffentlichen, in der sie mit Kommentaren im Code versehen ist. Dort ist alles einfach.Uart13.h-Headerdatei
#ifndef _UART13_H_
#define _UART13_H_ 1
#include <avr/io.h>
#include <avr/interrupt.h>
#define TXPORT PORTB
#define RXPORT PINB
#define TXDDR DDRB
#define RXDDR DDRB
#define TXD 0
#define RXD 1
#define T_DIV 0x02
#define BAUD_DIV 0x7D
volatile uint16_t txbyte;
volatile uint8_t rxbyte;
volatile uint8_t txbitcount;
volatile uint8_t rxbitcount;
void uart_init();
void uart_send(uint8_t tb);
int16_t uart_recieve(uint8_t* rb);
#endif
Aber ich werde die Beschreibung des Bibliotheksimplementierungscodes in Teile zerlegen, um den Artikel nicht in einen riesigen Spoiler mit Code zu verwandeln.Unterbrechen Sie TIM0_COMPAISR(TIM0_COMPA_vect)
{
TXPORT = (TXPORT & ~(1 << TXD)) | ((txbyte & 0x01) << TXD);
txbyte = (txbyte >> 0x01) + 0x8000;
if(txbitcount > 0)
{
txbitcount--;
}
}
OCR0A. , , OCR0A. , TCNT0 ( CTC, TCCR0A). UART. txbyte : , , txbyte TXD , , .
Solange keine Daten zu übertragen sind, wird die Nummer 0xFFFF in der Variablen gespeichert und daher wird am TXD-Ausgang kontinuierlich ein hoher Logikpegel aufrechterhalten. Wenn wir Daten übertragen möchten, müssen wir die Anzahl der zu übertragenden Bits in den Bitzähler schreiben: 1 Start, 8 Datenbits und 1 Stopp für insgesamt 10 (0x0A) und txbyte-Daten für die Übertragung zusammen mit dem Startbit eingeben. Danach werden sie sofort übertragen. Die Funktion void uart_send (uint8_t tb) ist an der Bildung des Pakets beteiligt.Unterbrechen Sie TIM0_COMPBISR(TIM0_COMPB_vect)
{
if(RXPORT & (1 << RXD))
rxbyte |= 0x80;
if(--rxbitcount == 0)
{
TIMSK0 &= ~(1 << OCIE0B);
TIFR0 |= (1 << OCF0B);
GIFR |= (1 << INTF0);
GIMSK |= (1 << INT0);
}
else
{
rxbyte >>= 0x01;
}
}
OCR0B. TIM0_COMPA, , , TCNT0. , , . , RXD , , rxbyte, , , . rxbyte, .
INT0ISR(INT0_vect)
{
rxbitcount = 0x09;
rxbyte = 0x00;
if(TCNT0 < (BAUD_DIV / 2))
{
OCR0B = TCNT0 + (BAUD_DIV / 2);
}
else
{
OCR0B = TCNT0 - (BAUD_DIV / 2);
}
GIMSK &= ~(1 << INT0);
TIFR0 |= (1 << OCF0A) | (1 << OCF0B);
TIMSK0 |= (1 << OCIE0B);
}
INT0. INT0, . 9, rxbyte. OCR0B, TIM0_COMPB, . TIM0_COMPB , INT0 .
UART.
uart_sendvoid uart_send(uint8_t tb)
{
while(txbitcount);
txbyte = (tb + 0xFF00) << 0x01;
txbitcount = 0x0A;
}
UART. , . , , 8 txbyte , 8 0xFF, , . 10.
uart_recieveint16_t uart_recieve(uint8_t* rb)
{
if(rxbitcount < 0x09)
{
while(rxbitcount);
*rb = rxbyte;
rxbitcount = 0x09;
return (*rb);
}
else
{
return (-1);
}
}
UART. 8- , . , , , (-1). , . , , (-1).
uart_initvoid uart_init()
{
txbyte = 0xFFFF;
rxbyte = 0x00;
txbitcount = 0x00;
rxbitcount = 0x09;
TXDDR |= (1 << TXD);
RXDDR &= ~(1 << RXD);
TXPORT |= (1 << TXD);
RXPORT |= (1 << RXD);
OCR0A = BAUD_DIV;
TIMSK0 |= (1 << OCIE0A);
TCCR0A |= (1 << WGM01);
TCCR0B |= T_DIV;
MCUCR |= (1 << ISC01);
GIMSK |= (1 << INT0);
sei();
}
UART-Initialisierungsfunktion. Keine Argumente, kein Rückgabewert. Initialisiert globale Variablen und Mikrocontroller-Register. Aus den Kommentaren im Code sollte alles klar sein.Es ist also Zeit, ein einfaches main () in unsere Bibliothek zu schreiben und zu sehen, was in Bezug auf die Codemenge passiert ist, und die Leistung zu überprüfen.Haupt c#include "uart13.h"
int main(void)
{
uint8_t b = 0;
uart_init();
while (1)
{
if(uart_recieve(&b) >= 0)
uart_send(b);
}
return (0);
}
Wir kompilieren:Programmspeicherauslastung: 482 Byte 47,1% Vollständiger
Datenspeicherbedarf: 5 Byte 7,8% Vollauslastung
Nicht schlecht, wir haben sogar mehr als die Hälfte des Speichers des Mikrocontrollers auf Lager!Einchecken in Proteus:Die Simulation ist in Ordnung! : , , delay.h , .
, avr-gcc:
GitHub