Главная » Микроконтроллеры » ATtiny13 — программный UART (отладчик)

ATtiny13 — программный UART (отладчик)

Поскольку микроконтроллер ATtiny13 не имеет аппаратного USART / UART, то в некоторых случаях мы вынуждены использовать программный UART.

Сегодня в этой статье представляем вам простой битовый UART. Скомпилированный для TX и RX, он использует всего 248 байт флеш-памяти.

Блок питания 0...30 В / 3A
Набор для сборки регулируемого блока питания...
Подробнее

Конфигурация последовательного порта по умолчанию — 8/N/1 на скорости 19200 бод (самый низкий уровень ошибок во время тестов). Скорость передачи данных можно легко изменить на другую стандартную скорость RS-232.

Обратите внимание, что это отличное решение для простой отладки / регистрации, но для других целей я бы рекомендовал использовать AVR со встроенным UART. Код находится на Github, нажмите здесь.

Дополнение: чтобы упростить интеграцию с внешними проектами, создана небольшая библиотека:

Требуемые детали

  • ATtiny13 — плата разработки
Плата разработки Attiny13
Attiny13A, кнопка сброса, две отдельные кнопки, два светодиода, потенциометр, 5В или 3,3 В...
Подробнее

Принципиальная электрическая схема

Инструменты последовательной связи

1) Последовательный адаптер TTL (преобразователь UART <-> USB)

 

2) Последовательный терминал

Я обычно использую CuteCom — графическую программу связи через последовательный порт, похожую на Minicom.

Программный код

Код программногоUART для Attiny13 написан на C. Скомпилировать его можно с помощью avr-gcc. Более подробная информация о том, как скомпилировать этот проект, находится здесь.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.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   (19200)
#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 unsupported - use higher UART_BAUDRATE
#endif

static char uart_getc();
static void uart_putc(char c);
static void uart_puts(const char *s);

int
main(void)
{
    char c, *p, buff[16];

    uart_puts("Hello World!\n");

    /* loop */
    while (1) {
        p = buff;
        while((c = uart_getc()) != '\n' && (p - buff) < 16) {
            *(p++) = c;
        }
        *p = 0;
        _delay_ms(10);
        uart_puts(buff);
    }
}

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++));
}

Источник

Цифровой мультиметр AN8009
Большой ЖК-дисплей с подсветкой, 9999 отсчетов, измерение TrueRMS...
Подробнее

Оставить комментарий

Ваш email нигде не будет показан. Обязательные для заполнения поля помечены *

*