Skip to content

Instantly share code, notes, and snippets.

@doorbash
Created December 8, 2019 19:21
Show Gist options
  • Save doorbash/441f121a3cd55e5358c4a09f643b96b9 to your computer and use it in GitHub Desktop.
Save doorbash/441f121a3cd55e5358c4a09f643b96b9 to your computer and use it in GitHub Desktop.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#ifndef _UART_H_
#define _UART_H_
#define UART_RX_ENABLED (1) // Enable UART RX
#define UART_TX_ENABLED (1) // Enable UART TX
#ifndef F_CPU
# define F_CPU (1200000UL) // 1.2 MHz
#endif /* !F_CPU */
#if defined(UART_TX_ENABLED) && !defined(UART_TX)
# define UART_TX PB3 // Use PB3 as TX pin
#endif /* !UART_TX */
#if defined(UART_RX_ENABLED) && !defined(UART_RX)
# define UART_RX PB4 // Use PB4 as RX pin
#endif /* !UART_RX */
#if (defined(UART_TX_ENABLED) || defined(UART_RX_ENABLED)) && !defined(UART_BAUDRATE)
# define UART_BAUDRATE (9600)
#endif /* !UART_BAUDRATE */
#define TXDELAY (int)(((F_CPU/UART_BAUDRATE)-7 +1.5)/3)
#define RXDELAY (int)(((F_CPU/UART_BAUDRATE)-5 +1.5)/3)
#define RXDELAY2 (int)((RXDELAY*1.5)-2.5)
#define RXROUNDED (((F_CPU/UART_BAUDRATE)-5 +2)/3)
#if RXROUNDED > 127
# error Low baud rates are not supported - use higher, UART_BAUDRATE
#endif
char uart_getc(void);
void uart_putc(char c);
void uart_putu(uint16_t x);
void uart_puts(const char *s);
#endif /* !_UART_H_ */
char uart_getc(void)
{
#ifdef UART_RX_ENABLED
char c;
uint8_t sreg;
sreg = SREG;
cli();
PORTB &= ~(1 << UART_RX);
DDRB &= ~(1 << UART_RX);
__asm volatile(
" ldi r18, %[rxdelay2] \n\t" // 1.5 bit delay
" ldi %0, 0x80 \n\t" // bit shift counter
"WaitStart: \n\t"
" sbic %[uart_port]-2, %[uart_pin] \n\t" // wait for start edge
" rjmp WaitStart \n\t"
"RxBit: \n\t"
// 6 cycle loop + delay - total = 5 + 3*r22
// delay (3 cycle * r18) -1 and clear carry with subi
" subi r18, 1 \n\t"
" brne RxBit \n\t"
" ldi r18, %[rxdelay] \n\t"
" sbic %[uart_port]-2, %[uart_pin] \n\t" // check UART PIN
" sec \n\t"
" ror %0 \n\t"
" brcc RxBit \n\t"
"StopBit: \n\t"
" dec r18 \n\t"
" brne StopBit \n\t"
: "=r" (c)
: [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
[uart_pin] "I" (UART_RX),
[rxdelay] "I" (RXDELAY),
[rxdelay2] "I" (RXDELAY2)
: "r0","r18","r19"
);
SREG = sreg;
return c;
#else
return (-1);
#endif /* !UART_RX_ENABLED */
}
void uart_putc(char c)
{
#ifdef UART_TX_ENABLED
uint8_t sreg;
sreg = SREG;
cli();
PORTB |= 1 << UART_TX;
DDRB |= 1 << UART_TX;
__asm volatile(
" cbi %[uart_port], %[uart_pin] \n\t" // start bit
" in r0, %[uart_port] \n\t"
" ldi r30, 3 \n\t" // stop bit + idle state
" ldi r28, %[txdelay] \n\t"
"TxLoop: \n\t"
// 8 cycle loop + delay - total = 7 + 3*r22
" mov r29, r28 \n\t"
"TxDelay: \n\t"
// delay (3 cycle * delayCount) - 1
" dec r29 \n\t"
" brne TxDelay \n\t"
" bst %[ch], 0 \n\t"
" bld r0, %[uart_pin] \n\t"
" lsr r30 \n\t"
" ror %[ch] \n\t"
" out %[uart_port], r0 \n\t"
" brne TxLoop \n\t"
:
: [uart_port] "I" (_SFR_IO_ADDR(PORTB)),
[uart_pin] "I" (UART_TX),
[txdelay] "I" (TXDELAY),
[ch] "r" (c)
: "r0","r28","r29","r30"
);
SREG = sreg;
#endif /* !UART_TX_ENABLED */
}
void uart_puts(const char *s)
{
while (*s) uart_putc(*(s++));
}
unsigned long time;
bool isOn;
int main(void)
{
char c;
pinMode(2, OUTPUT);
while (1) {
c = uart_getc();
if(c == 'Y') {
isOn = true;
digitalWrite(2, HIGH);
} else if(c == 'N') {
isOn = false;
digitalWrite(2, LOW);
} else if(c == 'T') {
if(isOn) {
isOn = false;
digitalWrite(2, LOW);
} else {
isOn = true;
digitalWrite(2, HIGH);
}
} else if(c == 'S') {
uart_putc(isOn ? 'y' : 'n');
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment