AVR單片機教程——串口發送

到目前爲止,咱們的開發板只能處理很小量的數據:讀取幾個引腳電平,輸出幾個LED,頂多用數碼管顯示一個兩位數字。至於輸入一個指令、輸出一條調試信息,甚至用scanfprintf來輸入輸出,在已經接觸過的這些器件上是不可思議的。而本講「串口發送」與下一講「串口接收」,將打開這一扇大門。html

硬件

本講的主題是UART(Universal Asynchronous Receiver-Transmitter,通用異步收發器),俗稱串口。實際上串口是串行接口的統稱,在單片機領域一般指UART。「串行」的意思是每次傳輸一個bit,而一個字節的數據被拆成8個bit傳輸;相比之下並行總線能夠一次傳輸一個或多個字節(這並不意味着並行總線必定優於串行總線)。編程

AVR單片機提供的硬件組件不是UART,而是USART(S表明Synchronous,同步的),相比UART額外支持同步通訊。所謂「同步」是指收發雙方經過時鐘同步,「異步」是指沒有時鐘來同步,但實際上雙方仍是由一些特殊信號同步的。安全

數據在UART總線上以「幀(frame)」爲單位發送,以下圖所示,帶有方括號的位是可選的。異步

一幀包含一個起始位、5~9個數據位(經常使用8位;不少設備不支持9位)、可選的一個校驗位(偶校驗或奇校驗,即全部數據位與0或1的異或結果)與1或2個終止位。起始位與終止位統稱爲同步位,用於在異步總線上起到同步的做用,這樣接收方纔能知道一幀什麼時候開始。函數

波特率的定義是信息在通訊信道上傳輸的速率。假如信號線上的波形容許1秒有9600個方框(方框表示高電平或低電平,實際電平是其中一個),那麼波特率就是9600。經常使用的波特率有9600與115200(打開Serial Port Utility或相似軟件,可選的波特率都是經常使用的)。ui

在開始通訊以前,收發雙方必須約定好波特率與幀格式。uart_init函數的配置是波特率38400,8數據位,偶校驗,1中止位。相應地在電腦的串口調試軟件中也要這樣配置。編碼

軟件

因爲printf是變參函數,不是很安全(若是格式串和參數對應錯,程序可能直接跑飛),我傾向於使用類型安全的函數,即函數經過C的句法知道實參類型(寫錯就編譯錯誤,而不是經過編譯器沒法檢測的格式串)。不過,avr-gcc的<stdio.h>中仍是提供了printf等函數,你能夠瞭解一下3d

庫中提供的發送函數都是同步阻塞的,即等待硬件組件把數據所有發送完,函數才返回。這裏的「同步」與剛纔的「異步總線」所指是不一樣的。關於「同步」與「異步」、「阻塞」與「非阻塞」的概念,能夠參考:怎樣理解阻塞非阻塞與同步異步的區別?調試

不難計算,總線發送一個字節的時間是幾千個CPU週期,CPU會浪費大量時間在無用的等待上。這個問題直到咱們講到中斷纔會解決(也許我會把它封裝起來放進庫)。code

實例

咱們來寫一個用串口發送按鍵與撥動開關信息的程序。若是你會相關的C#編程,就可讓電腦響應按鍵事件。

#include <ee1/delay.h>
#include <ee1/button.h>
#include <ee1/switch.h>
#include <ee1/uart.h>

int main(void)
{
    button_init(PIN_6, PIN_7);
    switch_init(PIN_4, PIN_5);
    uart_init(UART_TX);
    uart_print_string("start\n");
    while (1)
    {
        for (uint8_t i = 0; i != BUTTON_COUNT; ++i)
            if (button_pressed(i))
            {
                uart_print_string("button ");
                uart_print_int(i);
                uart_print_string("\n");
            }
        for (uint8_t i = 0; i != SWITCH_COUNT; ++i)
            if (switch_changed(i))
            {
                uart_print_string("switch ");
                uart_print_int(i);
                uart_print_string(switch_status(i) ? " on\n" : " off\n");
            }
        delay(1);
    }
}

程序首先將UART初始化爲發送模式(UART_TX),而後打印"start"。在間隔一毫秒的循環中(實際上串口發送的時間遠長於一毫秒,由於是阻塞的),程序檢測每個按鍵與開關的動做,若是有則發送相應數據。

printf一行就能解決的操做這裏須要三行才能完成,這就是權衡吧。

做業

  1. 基於uart_print_char,實現my_print_int函數,在串口上打印一個int類型整數(在avr-gcc中,int類型默認是16位寬度;注意負號和0;你能夠了解一下itoa,儘管它是非標準的)。

  2. 將旋轉編碼器的數據經過串口傳輸給電腦。將原始數據(pin_readrotary_status)與處理後的數據(rotary_rotated)一同打印,你能夠更直觀地感覺數據處理的過程。

相關文章
相關標籤/搜索