├── serial.cpp ├── serial.h └── test.cpp /serial.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "serial.h" 4 | 5 | void serial_init() { 6 | #ifdef SERIAL_SEND 7 | DDRB |= 1 << SERIAL_SEND; // Set transmit as output 8 | PORTB |= 1 << SERIAL_SEND; // Set high (inactive) 9 | #endif 10 | 11 | #ifdef SERIAL_RECEIVE 12 | DDRB &= ~(1 << SERIAL_RECEIVE); 13 | 14 | TCCR0A |= 1 << WGM01; // clear on compare 15 | TCCR0B |= (1 << CS01) | (1 << CS00); // set timer clock to 0b011 (clock/64) 16 | 17 | GIMSK = 1 << PCIE; // general intertupt mask enable pin change int 18 | PCMSK |= 1 << SERIAL_RECEIVE; // Pin change mask? 19 | sei(); // set int enabled 20 | #endif 21 | } 22 | 23 | #ifdef SERIAL_SEND 24 | void serial_send(unsigned char val) { 25 | PORTB &= ~(1 << SERIAL_SEND); // Set low 26 | _delay_us(1000000 / SERIAL_RATE); // Wait 27 | 28 | for (char i = 0; i < 8; ++i) { // Loop bits 29 | PORTB = (PORTB & ~(1 << SERIAL_SEND)) | (((val >> i) & 1) << SERIAL_SEND); // Set port to each bit 30 | _delay_us(1000000 / SERIAL_RATE); // Wait 31 | } 32 | 33 | PORTB |= 1 << SERIAL_SEND; // Send stop bit 34 | _delay_us(1000000 / SERIAL_RATE); // Wait 35 | } 36 | #endif 37 | 38 | #ifdef SERIAL_RECEIVE 39 | volatile unsigned char position; // Current position within byte 40 | volatile unsigned char data; // Recieved byte 41 | 42 | /* 43 | WARNING: Receive uses inverted logic, designed to be used with an inverting level shifter 44 | */ 45 | ISR(TIM0_COMPA_vect) { // Timer interrupt 46 | if (!(PINB & (1 << SERIAL_RECEIVE))) { // If current bit is set 47 | data |= (1 << position); // Set corresponding bit in recieved byte 48 | } 49 | 50 | if (++position == 8) { // If at end of byte 51 | TIMSK0 &= ~(1 << OCIE0A); // Disable interrupt for compare register A (this interrupt) 52 | serial_receive(data); // Alert user they have data 53 | PCMSK |= 1 << SERIAL_RECEIVE; // Enable pin change interrupt to start next byte 54 | } else { 55 | OCR0A = SERIAL_BIT_TIME; // Set delay time equal to the length of a single bit 56 | } 57 | } 58 | 59 | /* 60 | WARNING: Receive uses inverted logic, designed to be used with an inverting level shifter 61 | */ 62 | ISR(PCINT0_vect) { // On pin change 63 | if (PINB & (1 << SERIAL_RECEIVE)) { // If is a start bit 64 | TCNT0 = 0; // Set counter to 0 65 | OCR0A = SERIAL_BIT_TIME * 1.5; // Call timer interrupt in middle of first bit 66 | position = 0; // Reset position and data 67 | data = 0; 68 | TIMSK0 |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt) 69 | TIFR0 |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there 70 | PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt 71 | } 72 | } 73 | #endif 74 | -------------------------------------------------------------------------------- /serial.h: -------------------------------------------------------------------------------- 1 | #define SERIAL_SEND 3 2 | #define SERIAL_RECEIVE 4 3 | #define SERIAL_RATE 9600 4 | 5 | #define SERIAL_BIT_TIME (1000000.0 / SERIAL_RATE) / (1.0 / 9.6 * 64) 6 | 7 | void serial_init(); 8 | 9 | #ifdef SERIAL_SEND 10 | void serial_send(unsigned char data); 11 | #endif 12 | 13 | void serial_receive(unsigned char data); 14 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | 3 | unsigned char buffer[10]; // 10 byte buffer 4 | 5 | int main() { 6 | serial_init(); // Initialise UART 7 | 8 | while(1); // Do a heap of useful calculations 9 | } 10 | 11 | unsigned char index; // Current index of buffer 12 | 13 | void serial_receive(unsigned char value) { // Called when a byte is received 14 | buffer[index] = value; // Set buffer at index to value 15 | 16 | if (++index == 10) { // If buffer is full 17 | for (int i = 0; i < 10; ++i) { // Loop buffer 18 | serial_send(buffer[i]); // Send byte 19 | } 20 | 21 | index = 0; // Reset index 22 | } 23 | } 24 | --------------------------------------------------------------------------------