一、STC15系列單片機的串口個數(shù)
在使用單片機的串口前,得先知道所使用的單片機有幾個串口,再結(jié)合你的硬件電路圖來使用哪個串口。
以下是STC15各系列單片機的串口數(shù)量,STC15W4K32S4系列有4個串口
二、串口的工作模式
工作模式0:同步移位寄存器(官方建議初學(xué)者不學(xué))
工作模式1:8位串口,波特率可變
工作模式2:9位串口,波特率固定(官方建議不學(xué)習(xí))
工作模式3:9位串口,波特率可變
三、與串口工作相關(guān)的寄存器
以串口1為例,與串口1相關(guān)的寄存器
1、串行控制寄存器
STC15系列單片機串口1的控制相關(guān)的寄存器有SCON和PCON;
通過SCON寄存器中的SM0和SM1位來設(shè)置工作方式,設(shè)置如下表格所示,最常用的是工作方式1?
REN:串口接收使能位,REN = 1,啟動串口接收,開始接收信息,REN = 0,禁止接收數(shù)據(jù);
TB8:工作在9位UART模式才有效,也就是方式2和3,表示要發(fā)送的第9位;也就是奇偶校驗位,8位UART不需要用這個位;
RB9:工作在9位UART模式才有效,也就是方式2和3,表示要接收的第9位;也就是奇偶校驗位,8位UART不需要用這個位;
TI:發(fā)送中斷請求標志位,在方式1,2,3中,在停止位開始發(fā)送的時候,單片機將TI位,置1,也就是TI = 1,向CPU發(fā)出中斷申請,響應(yīng)中斷后,TI必須由軟件清零,也就是用戶要在代碼中寫上TI = 0;
RI:接收中斷請求標志位,在方式1,2,3中,串行接收到停止位的終點時刻,單片機將RI位,置1,也就是RI = 1,向CPU發(fā)出中斷申請,響應(yīng)中斷后,RI必須由軟件清零,也就是用戶要在代碼中寫上RI = 0;
電源控制寄存器PCON用來設(shè)置串口1的波特率是否加倍,PCON中與串口1相關(guān)的位只有SMOD和SMOD0
SMOD:波特率選擇位,當SMOD = 1,串口波特率加倍;當SMOD = 0,波特率不加倍,默認是SMOD = 0;
SMOD0:幀錯誤檢測有效控制位。這個位能決定SCON寄存器中SM0/FE位的功能,SMOD0 = 1時,SM0/FE位的功能是FE(幀錯誤檢測),SMOD0 = 0時,SM0/FE位的功能是SM0功能,復(fù)位時SMOD0 = 0;
2、串行口數(shù)據(jù)緩沖寄存器SBUF
數(shù)據(jù)緩沖寄存器器,分為數(shù)據(jù)接收緩沖器和數(shù)據(jù)發(fā)送緩沖器,它們可以同時工作,也就是說,串口可以同時發(fā)送數(shù)據(jù)和接收數(shù)據(jù)。
數(shù)據(jù)接收緩沖器只能讀出,不能寫入;
數(shù)據(jù)發(fā)送緩沖器只能寫入,不能讀出;
數(shù)據(jù)接收緩沖器與數(shù)據(jù)發(fā)送緩沖器的地址是一樣的,比如
串口1的數(shù)據(jù)接收與發(fā)送緩沖器的地址都是99H,在官方頭文件中定義的名字都是SBUF;
串口發(fā)送數(shù)據(jù):
單片機只要執(zhí)行了寫SBUF命令,(匯編指令:MOV? ? SBUF, A)或者 (C語言指令SBUF = XX),要發(fā)送的數(shù)據(jù)(一個字節(jié))就會裝入相同的9位移位寄存器,前面8位是數(shù)據(jù)字節(jié),第9位可以根據(jù)工作模式來設(shè)置,9位串口設(shè)置為TB的值,8位串口設(shè)置為1;
串口接收數(shù)據(jù):
串口的接收急促器本身就是一個輸入移位寄存器,串口在工作模式1,2,3,移位寄存器為9位,當一幀數(shù)據(jù)接收完畢,移位寄存器中的數(shù)據(jù)字節(jié)(前8位)裝入數(shù)據(jù)接收緩沖器SBUF,第9位裝入SCON寄存器的RB8位。當一幀數(shù)據(jù)從移位寄存器裝入SBUF后,可立即開始接收下一幀數(shù)據(jù),用戶應(yīng)該在下一幀數(shù)據(jù)接收結(jié)束前將數(shù)據(jù)從SBUF中取走,否則數(shù)據(jù)就被覆蓋了。
3、輔助寄存器AUXR
官方推薦用定時器T2作為串口1的波特率發(fā)生器,那就從了他吧,相關(guān)的AUXR寄存器位是T2x12和S1ST2.
T2x12:定時器2速度控制位,T2x12 = 0,12T 模式,T2x12 = 1,1T 模式,
S1ST2:串口1選擇哪個定時器作為波特率發(fā)生器控制位,S1ST2 = 0,選擇定時1作為串口 1的波特率發(fā)生器,S1ST2 = 1,選擇定時2作為串口 1的波特率發(fā)生器。默認S1ST2 = 1;
4、定時器2的寄存器T2H,T2L
定時器2的寄存器T2H和寄存器T2L是定時器用來保存重裝時間。
5、與串口1中斷相關(guān)的寄存器位ES,PS
EA:CPU的中斷總開關(guān)控制位,EA= 1,使能中斷,EA= 0,禁止所有中斷;
ES:串行口中斷允許控制位,ES = 1,允許串口中斷;ES= 0,禁止串口中斷;
?PS:串口1的中斷優(yōu)先級控制位,PS=0,串口1的中斷優(yōu)先級為0,最低優(yōu)先級;PS= 1,串口1的中斷優(yōu)先級為1,最高優(yōu)先級
6、控制串口1相關(guān)引腳的寄存器AUXR1
四、用戶在程序中如何使用串口
以串口1為例,使用串口的步驟如下
1、設(shè)置串口1的工作模式,使用串行控制寄存器SCON中的SM0和SM1這兩位來設(shè)置工作模式;
2、設(shè)置串口1的波特率,使用定時器2的寄存器T2H和T2L;
3、設(shè)置定時器2的速度1T還是12T,使用輔助寄存器AUXR中的T2x12位;
4、啟動定時器2,通過設(shè)置T2R位為1,定時器2就開始計數(shù);
5、設(shè)置串口1的中斷優(yōu)先級,并打開中斷,打開中斷需要打開PS、ES、EA這些控制位;
6、如果串口1是接收數(shù)據(jù),將REN位設(shè)置為1就可以;如果串口1是發(fā)送數(shù)據(jù),將數(shù)據(jù)送入SBUF就可以;
7、數(shù)據(jù)接收完成,標志位RI自動置1;數(shù)據(jù)發(fā)送完成,標志位TI自動置1;RI和TI都需要軟件清0;
波特率的計算
串口1的波特率 = 定時器T2的溢出率 / 4;
STC15系列單片機我們一般用它工作在1T模式,這個通過AUXR來設(shè)置,
定時器2的溢出率 = SYSclk / (65536-[RL_TH2, RL+TL2]);
則串口1的波特率 =?SYSclk / (65536-[RL_TH2, RL+TL2])/4
五、串口1工作模式1:8位UART,波特率可變
六、串口1的工作模式3: 9位UART,波特率可變
?
七、串口應(yīng)用代碼示例
程序示例2:?文章來源:http://www.zghlxwxcb.cn/news/detail-849788.html
#include <STC15.H>
#include <intrins.h>
#define FOSC 11059200L
#define BAUD 115200
#define NONE_PARITY 0
#define ODD_PARTITY 1
#define EVEN_PARTITY 2
#define MARK_PARTITY 3
#define SPACE_PARTITY 4
#define PARITYBIT EVEN_PARTITY
typedef unsigned char BYTE;
typedef unsigned int WORD;
bit busy;
BYTE flag = 0;
void SendDate(BYTE dat);
void SendString(char *s);
void main(void)
{
#if(PARITYBIT == NONE_PARITY)
SCON = 0x50;//8位可變波特率
#elif(PARITYBIT == ODD_PARTITY)||(PARITYBIT == EVEN_PARTITY)||(PARITYBIT == MARK_PARTITY)
SCON = 0xDA;//9位可變波特率,校驗初始位為1
#elif(PARITYBIT == SPACE_PARTITY)
SCON = 0xDa;//9位可變波特率,校驗初始位為0
#endif
T2L = (65536-(FOSC/4/BAUD));
T2H = (65536-(FOSC/4/BAUD)) >> 8;
AUXR = 0x14;//T2為1T模式,并啟動定時器2
AUXR |= 0x01;//選擇T2作為串口1的波特率發(fā)生器
ES = 1;//使能串口1中斷
EA = 1; //打開中斷總開關(guān)
while(1)
{
if(flag == 1)
{
SendString("STC15W4K\r\n");
flag = 0;
}
}
}
void Uart_ISR() interrupt 4
{
if(RI)
{
RI = 0;//清除RI位
flag = 1;
}
if(TI)
{
TI = 0; //清除TI
busy = 0; //清除忙標志位
}
}
void SendData(BYTE dat)
{
while(busy);//等待前面的數(shù)據(jù)發(fā)送完成
ACC = dat;//獲取校驗位P,PSW.0
if(P)
{
#if(PARITYBIT == ODD_PARTITY)
TB8 = 0;//設(shè)置校驗位為0
#elif(PARITYBIT == EVEN_PARTITY)
TB8 = 1;//設(shè)置校驗位為1
#endif
}
else
{
#if(PARITYBIT == ODD_PARTITY)
TB8 = 1;//設(shè)置校驗位為1
#elif(PARITYBIT == EVEN_PARTITY)
TB8 = 0;//設(shè)置校驗位為0
#endif
}
busy = 1;
SBUF = ACC; //寫數(shù)據(jù)到UART數(shù)據(jù)寄存器
}
void SendString(char *s)
{
while(*s) //檢查字符串結(jié)束標志
{
SendData(*s++); //發(fā)送當前字符
}
}
程序?qū)嵗?:文章來源地址http://www.zghlxwxcb.cn/news/detail-849788.html
#include <STC15.H> //包含頭文件,一般情況不需要改動,頭文件包含特殊功能寄存器的定義
#include <intrins.h>
/*------------------------------------------------
函數(shù)聲明
------------------------------------------------*/
/************* 功能說明 **************
串口1全雙工中斷方式收發(fā)通訊程序。本例程使用11.0592MHZ時鐘,如要改變,請修改下面的"定義主時鐘"的值并重新編譯。
串口設(shè)置為:115200,8,n,1.
通過PC向MCU發(fā)送數(shù)據(jù), MCU收到后通過串口把收到的數(shù)據(jù)原樣返回.
******************************************/
/************* 本地常量聲明 **************/
//#define MAIN_Fosc 22118400L //定義主時鐘
#define MAIN_Fosc 11059200L //定義主時鐘
#define RX1_Lenth 32 //串口接收緩沖長度
#define BaudRate1 115200UL //選擇波特率
#define Timer1_Reload (65536UL -(MAIN_Fosc / 4 / BaudRate1)) //Timer 1 重裝值, 對應(yīng)300KHZ
#define Timer2_Reload (65536UL -(MAIN_Fosc / 4 / BaudRate1)) //Timer 2 重裝值, 對應(yīng)300KHZ
#define S1_DoubleRate() PCON |= 0x80
#define S1_SHIFT() SCON &= 0x3f
#define S1_8bit() SCON = (SCON & 0x3f) | 0x40
#define S1_9bit() SCON = (SCON & 0x3f) | 0xc0
#define S1_RX_Enable() SCON |= 0x10
#define S1_USE_P30P31() P_SW1 &= ~0xc0 //UART1 使用P30 P31口 默認
#define S1_USE_P36P37() P_SW1 = (P_SW1 & ~0xc0) | 0x40 //UART1 使用P36 P37口
#define S1_USE_P16P17() P_SW1 = (P_SW1 & ~0xc0) | 0x80 //UART1 使用P16 P17口
#define S1_TXD_RXD_SHORT() PCON2 |= (1<<4) //將TXD與RXD連接中繼輸出
#define S1_TXD_RXD_OPEN() PCON2 &= ~(1<<4) //將TXD與RXD連接中繼斷開 默認
#define S1_BRT_UseTimer2() AUXR |= 1
#define S1_BRT_UseTimer1() AUXR &= ~1
/************* 本地變量聲明 **************/
unsigned char RX1_Buffer[RX1_Lenth]; //接收緩沖
unsigned char TX1_Cnt; //發(fā)送計數(shù)
unsigned char RX1_Cnt; //接收計數(shù)
bit B_TX1_Busy; //發(fā)送忙標志
/************* 本地函數(shù)聲明 **************/
/**********************************************/
void main(void)
{
B_TX1_Busy = 0;
RX1_Cnt = 0;
TX1_Cnt = 0;
//S1_8bit(); //8位數(shù)據(jù)
SCON = (SCON & 0x3f) | 0x40;
//S1_USE_P30P31(); //UART1 使用P30 P31口 默認
P_SW1 &= ~0xc0;
AUXR &= ~(1<<4); //Timer stop 波特率使用Timer2產(chǎn)生
AUXR |= 0x01; //串口1的波特率發(fā)生器使用Timer2
AUXR |= (1<<2); //Timer2 set as 1T mode
T2H = Timer2_Reload >> 8;
T2L = Timer2_Reload;
AUXR |= (1<<4); //Timer run enable
REN = 1; //允許接收
ES = 1; //允許中斷
EA = 1; //允許全局中斷
while (1)
{
if(TX1_Cnt != RX1_Cnt) //收到過數(shù)據(jù)
{
if(!B_TX1_Busy) //發(fā)送空閑
{
B_TX1_Busy = 1; //標志發(fā)送忙
SBUF = RX1_Buffer[TX1_Cnt]; //發(fā)一個字節(jié)
if(++TX1_Cnt >= RX1_Lenth) TX1_Cnt = 0; //避免溢出處理
}
}
}
}
/********************* UART1中斷函數(shù)************************/
void UART1_interrupt (void) interrupt 4
{
if(RI)
{
RI = 0;
RX1_Buffer[RX1_Cnt] = SBUF; //保存一個字節(jié)
if((++RX1_Cnt) >= RX1_Lenth)
{
RX1_Cnt = 0; //避免溢出處理
}
}
if(TI)
{
TI = 0;
B_TX1_Busy = 0; //清除發(fā)送忙標志
}
}
到了這里,關(guān)于STC15系列單片機學(xué)習(xí)4:串口通訊的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!