Jerry @DOA&INPAC, SJTU

Working out everything from the first principles.

导航

AVR单片机教程——串口接收

本文隶属于AVR单片机教程系列。

 

上一讲中,我们实现了单片机开发板向电脑传输数据。在这一讲中,我们将通过电脑向单片机发送指令,让单片机根据指令控制LED。这一次,两端的TX与RX需要交叉连接,单片机TX连接串口工具RX也是需要的,因为程序会根据指令反馈信息。

为了简单起见,我们的程序只需要控制4个板载LED。指令包含两个字节:第一个字节为rygb中的一个,分别表示红、黄、绿、蓝灯;第二个字节为01,表示灯不亮或亮。

然而,a2这样的指令是没有意义的,却是可能出现的。即使用户已经熟悉了这8条指令,也可能会不小心打错。我们应当记住,用户是世界上最愚蠢的人,我们要把他们可能犯的错误都想到,然后在程序中合理地处理。比如,对于不合法的指令,程序忽略指令,并返回What?给电脑;对于合法的,则执行并返回Done!

#include <ee1/led.h>
#include <ee1/uart.h>

int main(void)
{
    led_init();
    uart_init(UART_DUPLEX);
    char temp[3];
    while (1)
    {
        uart_scan_string_n(temp, 2);
        bool good = true;
        led_t led;
        switch (temp[0])
        {
            case 'r': led = LED_RED   ; break;
            case 'y': led = LED_YELLOW; break;
            case 'g': led = LED_GREEN ; break;
            case 'b': led = LED_BLUE  ; break;
            default:  good = false;     break;
        }
        bool on;
        switch (temp[1])
        {
            case '0': on = false;   break;
            case '1': on = true ;   break;
            default:  good = false; break;
        }
        if (good)
        {
            led_set(led, on);
            uart_print_string("Done!\n");
        }
        else
            uart_print_string("What?\n");
    }
}

while循环的周期是多少呢?没有delay语句,是不是循环在很快地扫描呢?不是,uart_scan_string_n函数一直等待直到串口接收到了规定量的数据。

实际上,这一系列串口接收的函数的功能非常受限——程序必须等待数据到来,不能错过它,这与scanf等函数从缓冲区读取数据不同。当然,单片机系统中的串口输入(以及输出)也可以实现缓冲区,并且是一种实用并常用的做法,但这要涉及到中断,是以后的内容。你可以试着利用数据手册以及其他资源实现一个带缓冲的串口输入输出。在avr-gcc中,使用中断要先#include <avr/interrupt.h>,串口接收中断写为ISR(USART0_RX_vect) { }

 

作业:

  1. 如果通过串口发送指令r11g1,只有红色LED会亮,因为程序对指令的解读是r11g1,而我只是不小心(故意)多打了一个1,本意是想让红色和绿色LED都亮。改进程序解决这个问题。

  2. 基于uart_scan_char,实现my_scan_int函数,从串口上读取十进制整数(注意正负号与溢出等;你可以了解一下atoi)。

posted on 2020-01-06 23:54  Jerry_SJTU  阅读(1672)  评论(0编辑  收藏  举报