第11章 UART串口通信
UART(Universal Asynchronous Receiver/Transmitter, 通用異步收發器)
波特率:baud,發送一位二進制數據的電平持續時間$ = \frac{1}{baud}$
在UART通信,規定:**當沒有通信信號發生時,通信線路保持高電平,當要發送數據之前,先一位0表示起始位,然後發送8位數據位,數據位是先低後高的順序,數據位發完後再發一位1表示停止位。
串口模塊的波特率發生器只能由定時器T1或定時器T2產生,而不能由定時器T0產生,默認是使用定時器1的模式2,定時器T1的重載值計算公式爲:TH1=TL1=256-晶振值/12/2/16/波特率
如果電源管理寄存器PCON的最高位=1,也就是如果PCON |=0x80;
,計算公式就寫爲:TH1=TL1=256-晶振值/12/16/波特率
;公式中的16重點說明,一位信號採集16次,取出第7、8、9次,如果這三次中有2次高電平,那麼就認爲是高電平,反之是低電平。
SBUF寄存器,地址:0x99
1. 利用定時器T0模擬串口通信程序
通過此程序能弄明白串口通信的原理
#include <reg52.h>
sbit TXD_PIN=P3^1; //
sbit RXD_PIN=P3^0; //
bit rxdOrTxd = 0; //
bit rxdEnd = 0; //
bit txdEnd = 0; //
unsigned char rxdBuf=0; //
unsigned char txdBuf=0; //
void configUART(unsigned int baud);
void startTx(unsigned char dat);
void startRx(void);
void main()
{
EA=1;
configUART(4800);
while(1)
{
while(!RXD_PIN); //
startRx();
while(!rxdEnd);
startTx(rxdBuf+1);
while(!txdEnd);
}
}
/**
* 名稱:configUART
* 功能:T0中斷配置函數
* 參數:baud——串口波特率
**/
void configUART(unsigned int baud)
{
unsigned int tmp;
tmp=12000000/12/baud; //256-TH0+(256-TH0)/2=
TH0=256-tmp;
TL0=TH0;
TMOD &=0XF0;
TMOD |=0x02;
}
/**
* 名稱:
* 功能:啓動串口接收
* 參數:
**/
void startRx()
{
TL0=256-((256-TH0)>>1); //開始接收時,波特率減半,增大週期爲原來的2倍
ET0=1;
TR0=1;
rxdOrTxd=0;
rxdEnd=0;
}
/**
* 名稱:
* 功能:啓動串口發送
* 參數:dat——要發送的字節
**/
void startTx(unsigned char dat)
{
txdBuf=dat; //
TL0=TH0; //
ET0=1; //
TR0=1; //
TXD_PIN=0; //發送起始位0
rxdOrTxd=1; //
txdEnd=0; //
}
/**
* 功能:T0中斷服務函數,完成接收或發送數據的處理。
* 參數:無
**/
void timer0() interrupt 1
{
static unsigned char cnt=0;
if (rxdOrTxd) //發送
{
cnt++; //
if (cnt <=8)
{
TXD_PIN =txdBuf & 0x01;
txdBuf >>= 1;
}
else if (cnt == 9)
{
TXD_PIN=1;
}
else
{
TR0=0;
ET0=0;
cnt=0;
txdEnd=1;
}
}
else //處理接收
{
if (cnt==0)
{
if (RXD_PIN)
{
TR0=0;
}
else
{
rxdBuf=0;
cnt++;
}
}
else if (cnt <=8)
{
rxdBuf >>=1;
if(RXD_PIN)
{
rxdBuf |= 0x80;
}
cnt++;
}
else
{
TR0=0;
cnt=0;
if (RXD_PIN)
{
rxdEnd=1;
}
}
}
}
2.串口演示例程
體驗指針和 sizeof()的用法。例程首先接收上位機下發的命令,根據命令值分別把不同數組的數據回發給上位機。在上位機串口調試助手中分別下發 1、2、3、4,就會得到不同的數組回發,注意這裏都用十六進制發送和十六進制顯示
#include <reg52.h>
bit cmdArrived=0; //
unsigned char cmdIndex=0; //
unsigned char cntTxd=0; //
unsigned char *ptrTxd; //
unsigned char a1[1]={1};
unsigned char a2[2]={1,2};
unsigned char a3[4]={1,2,3,4};
unsigned char a4[8]={1,2,3,4,5,6,7,8};
void configUART(unsigned int baud);
void main()
{
EA=1;
configUART(4800);
while(1)
{
if (cmdArrived)
{
cmdArrived=0;
switch(cmdIndex)
{
case(1): ptrTxd = a1; cntTxd=sizeof(a1);TI=1;break;
case(2): ptrTxd = a2; cntTxd=sizeof(a2);TI=1;break;
case(3): ptrTxd = a3; cntTxd=sizeof(a3);TI=1;break;
case(4): ptrTxd = a4; cntTxd=sizeof(a4);TI=1;break;
default: break;
}
}
}
}
/**
* 名稱:configUART
* 功能:T1中斷配置函數
* 參數:baud——串口波特率
**/
void configUART(unsigned int baud)
{
unsigned int tmp;
SCON=0X50; //配置串口爲模式1
TMOD &=0X0F; //
TMOD |=0x20;
tmp=12000000/12/2/16/baud; //
TH1=256-tmp;
TL1=TH0; //
ET1=0;
ES=1; //使能串口中斷
TR1=1;
}
/**
* 功能:串口中斷服務函數,完成接收或發送數據的處理。
* 參數:無
**/
void UART() interrupt 4
{
if(RI)
{
RI=0;
cmdIndex=SBUF;
cmdArrived=1;
}
if (TI)
{
TI=0;
if (cntTxd>0)
{
SBUF=*ptrTxd;
cntTxd=0;
ptrTxd++;
}
}
}
第12章 指針基礎與1602認識
sizeof()
操作,相當於一個常量,因它是在程序編譯的時候進行的,sizeof()括號中可以是變量名,也可以是變量類型名
- 常量:直接常量與符號常量
符號常量聲明的兩種方式:
: const 類型 符號常量名字 = 常量值;
: #define 符號常量名 常量值
字符型常量有兩種,普通字符和轉義字符
字符串常量在內存中按順序逐個存儲字符串中的字符的ASCII碼值,最後有一個字符’\0’
單片機讀外部狀態前,必須先保證自己是高電平
1602操作時序
#define LCD1602_DB P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E = P1^5;
- 讀狀態:RS=L, R/W=H, E=H;
LCD1602_DB = 0XFF;
LCD1602_RS=0;
LCD1602_RW=1;
LCD1602_E=1;
sta = LCD1602_DB;
如果1602設備處於忙的狀態,需要等待;由於P0總線被多個設備共用,因此需及時釋放P0總線,避免干擾其它設備的使用。因此改寫上面程序:
LCD1602_DB=0xFF;
LCD1602_RS=0;
LCD1602_RW=1;
do {
LCD1602_E=1;
sta=LCD1602_DB;
LCD1602_E=0;
} while(sta & 0x80)
-
讀數據:RS=H, R/W=L,E=H;
-
寫指令:RS=L, R/W=L, D0~D7=指令碼, E=高脈衝;
E=高脈衝的意思就是:E使能引腳先從低拉高,再從高拉低,形成一個高脈衝。 -
寫數據:RS=H, R/W=L, D0~D7=指令碼, E=高脈衝;