1.幾個電子通信的基本概念
-> 同步通信和異步通信:
同步通信中,通信雙方按照統一節拍工作,是以配合很好;一般需要發送方給接收方發送資訊同時發送時鐘信号.
異步通信又叫異步通知。在雙方通信的頻率不固定時(有時3ms收發一次,有時3天才收發一次)不适合使用同步通信,而适合異步通信。
-> 電平信号和差分信号:
電平信号的傳輸線中有一個參考電平線(一般是GND),然後信号線上的信号值是由信号線電平和參考電平線的電壓差決定。
差分信号的傳輸線中沒有參考電平,所有都是信号線。然後1和0的表達靠信号線之間的電壓差。
-> 并行接口和串行接口:
串行、并行主要是考慮通信線的根數,就是發送方和接收方同時可以傳遞的資訊量的多少。
譬如在電平信号下,1根參考電平線+1根信号線可以傳遞1位二進制;如果我們有3根線(2根信号線+1根參考線)就可以同時發送2位二進制;如果想同時發送8位二進制就需要9根線。
在差分信号下,2根線(彼此差分)可以同時發送1位二進制;如果需要同時發送8位二進制,需要16根線。
2.幾個序列槽通信的基本概念
-> RS232電平和TTL電平:
RS232電平中-3V~-15V表示1;+3~+15V表示0,台式電腦後面的序列槽插座就是RS232接口的,在工業上用序列槽時都用這個,傳輸距離小于15米。
TTL電平則是+5V表示1,0V表示0,TTL電平一般用在電路闆内部兩個晶片之間。
-> 波特率:
指的是序列槽通信的速率,也就是序列槽通信時每秒鐘可以傳輸多少個二進制位。譬如每秒種可以傳輸9600個二進制位(傳輸一個二進制位需要的時間是1/9600秒,也就是104us),波特率就是9600。
通信雙方必須事先設定相同的波特率這樣才能成功通信,常用就是9600或者115200。
-> 單工通信和雙工通信:
單工就是單方向,雙工就是雙方同時收發,同時隻能單方向但是方向可以改變叫半雙工
如果隻能A發B收則單工,A發B收或者B發A收(兩個方向不能同時)叫半雙工,A發B收同時B發A收叫全雙工。
-> 三根通信線:Rx Tx GND:
序列槽通信線最少需要2根(GND和信号線),可以實作單工通信,也可以使用3根通信線(Tx、Rx、GND)來實作全雙工。
-> 起始位、資料位、奇偶校驗位、停止位:
序列槽通信時,收發是一個周期一個周期進行的,每周期傳輸n個二進制位。這一個周期就叫做一個通信單元,一個通信單元是由:起始位+資料位+奇偶校驗位+停止位組成的。
起始位表示發送方要開始發送一個通信單元;資料位是一個通信單元中發送的有效資訊位;
奇偶校驗位是用來校驗資料位,以防止資料位出錯的;停止位是發送方用來表示本通信單元結束标志的。
-> FIFO模式:
發送/接收緩沖區隻有1位元組,每次發送/接收隻能處理1幀資料。這樣在單片機中沒什麼問題,但是到複雜SoC中(一般有作業系統的)就會有問題,會導緻效率低下,因為CPU需要不斷切換上下文。
3.序列槽通信的基本原理
整個序列槽控制器包含發送緩沖區transmitter和接收緩沖區receiver兩部分,兩部分功能彼此獨立,transmitter負責210向外部發送資訊,receiver負責從外部接收資訊到210内部。
transmitter由發送緩沖區和發送移位器構成,我們要發送資訊時,首先将資訊進行編碼(一般用ASCII碼)成二進制流,然後将一幀資料(一般是8位)寫入發送緩沖區(從這裡以後程式就不用管了,剩下的發送部分是硬體自動的),發送移位器會自動從發送緩沖區中讀取一幀資料,然後自動移位(移位的目的是将一幀資料的各個位分别拿出來)将其發送到Tx通信線上。
receiver由接收緩沖區和接收移位器構成。當有人通過序列槽線向我發送資訊時,資訊通過Rx通信線進入我的接收移位器,然後接收移位器自動移位将該二進制位儲存入我的接收緩沖區,接收完一幀資料後receiver會産生一個中斷給CPU,CPU收到中斷後即可知道receiver接收滿了一幀資料,就會來讀取這幀資料。
序列槽控制器中有一個波特率發生器,作用是産生序列槽發送/接收的節拍時鐘。
4.S5PV210串行通信程式設計實戰
硬體原理圖:Rx和Rx分别對應GPA0_1和GPA0_0

幾個重要的寄存器:
ULCON0 = 0x3 // 0校驗位、8資料位、1停止位
UCON = 0x5 // 發送和接收都是polling mode
UMCON0 = 0x0 // 禁止modem、afc
UFCON0 = 0x0 // 禁止FIFO模式
UBRDIV0和UDIVSLOT0和波特率有關,要根據公式去算的
整個序列槽通信相關程式包含2部分:
uart_init負責初始化序列槽,uart_putc負責發送一個位元組,char uart_getc負責接收一個位元組。
uart.h:
#define GPA0CON 0xE0200000
#define UCON0 0xE2900004
#define ULCON0 0xE2900000
#define UMCON0 0xE290000C
#define UFCON0 0xE2900008
#define UBRDIV0 0xE2900028
#define UDIVSLOT0 0xE290002C
#define UTRSTAT0 0xE2900010
#define UTXH0 0xE2900020
#define URXH0 0xE2900024
#define rGPA0CON (*(volatile unsigned int *)GPA0CON)
#define rUCON0 (*(volatile unsigned int *)UCON0)
#define rULCON0 (*(volatile unsigned int *)ULCON0)
#define rUMCON0 (*(volatile unsigned int *)UMCON0)
#define rUFCON0 (*(volatile unsigned int *)UFCON0)
#define rUBRDIV0 (*(volatile unsigned int *)UBRDIV0)
#define rUDIVSLOT0 (*(volatile unsigned int *)UDIVSLOT0)
#define rUTRSTAT0 (*(volatile unsigned int *)UTRSTAT0)
#define rUTXH0 (*(volatile unsigned int *)UTXH0)
#define rURXH0 (*(volatile unsigned int *)URXH0)
uart.c:
實作了序列槽的初始化,序列槽的發送函數,序列槽的接收函數。
// 序列槽初始化程式
void uart_init(void)
{
// 初始化Tx Rx對應的GPIO引腳
rGPA0CON &= ~(0xff<<0); // 把寄存器的bit0~7全部清零
rGPA0CON |= 0x00000022; // 0b0010, Rx Tx
// 幾個關鍵寄存器的設定
rULCON0 = 0x3;
rUCON0 = 0x5;
rUMCON0 = 0;
rUFCON0 = 0;
//波特率的計算和設定
//用PCLK_PSYS和目标波特率去計算DIV_VAL: DIV_VAL = (PCLK / (bps x 16)) -1
//UBRDIV0寄存器中寫入DIV_VAL的整數部分
//用小數部分*16得到1個個數,查表得uBDIVSLOT0寄存器的設定值
// 波特率設定 DIV_VAL = (PCLK / (bps x 16))-1
// PCLK_PSYS用66MHz算 餘數0.8
//rUBRDIV0 = 34;
//rUDIVSLOT0 = 0xdfdd;
// PCLK_PSYS用66.7MHz算 餘數0.18
// DIV_VAL = (66700000/(115200*16)-1) = 35.18
rUBRDIV0 = 35;
// (rUDIVSLOT中的1的個數)/16=上一步計算的餘數=0.18
// (rUDIVSLOT中的1的個數 = 16*0.18= 2.88 = 3
rUDIVSLOT0 = 0x0888; // 3個1,查官方推薦表得到這個數字
}
// 序列槽發送程式,發送一個位元組
void uart_putc(char c)
{
// 序列槽發送一個字元,其實就是把一個位元組丢到發送緩沖區中去
// 因為序列槽控制器發送1個位元組的速度遠遠低于CPU的速度,是以CPU發送1個位元組前必須
// 确認序列槽控制器目前緩沖區是空的(意思就是序列槽已經發完了上一個位元組)
// 如果緩沖區非空則位為0,此時應該循環,直到位為1
while (!(rUTRSTAT0 & (1<<1)));
rUTXH0 = c;
}
// 序列槽接收程式,輪詢方式,接收一個位元組
char uart_getc(void)
{
while (!(rUTRSTAT0 & (1<<0)));
return (rURXH0 & 0x0f);
}
main.c:
void main(void)
{
uart_init();
while(1)
{
uart_putc('a');
delay();
}
}