USART—通用同步異步收發(fā)接收器,是一個串行通信設(shè)備,可以和外部設(shè)備進行靈活的全雙工數(shù)據(jù)交換,有別于USART還有一個UART(在原來的基礎(chǔ)上裁剪掉了同步通信功能(時鐘同步)),串行通信一般是以幀格式傳輸數(shù)據(jù),一幀一幀的傳。
協(xié)議層:串口通信的一個數(shù)據(jù)包包含從起始信號開始,直到停止信號的結(jié)束 起始信號:一個邏輯0數(shù)據(jù)位表示。 停止信號:0.5,1,1.5或2個邏輯1的數(shù)據(jù)位表示。 0.5個停止位:智能卡模式下的接收數(shù)據(jù)時使用。 1個停止位:停止位的默認數(shù)值 1.5個停止位:智能卡模式下的手法數(shù)據(jù)和接收數(shù)據(jù)時使用 2個停止位:常規(guī)USART模式,單線模式以及調(diào)制解調(diào)器的模式。 有效數(shù)據(jù)的基本長度被約定為5,6,7,8. 奇偶檢驗(設(shè)置USART-CR1 的PS位) 偶檢驗:數(shù)據(jù)=00110101,里面數(shù)據(jù)1的個數(shù)位為偶數(shù)位,檢驗位置“0”,當(dāng)數(shù)據(jù)檢驗和偶數(shù)相同的時候,證明沒有出錯,反之則錯誤 奇檢驗:數(shù)據(jù) = 01110101,里面數(shù)據(jù)1的個數(shù)為奇檢位,檢驗位置“1”,當(dāng)數(shù)據(jù)檢驗和奇數(shù)相同,則證明沒有出錯,反之錯誤。 當(dāng)然也會存在同時兩個位一塊出現(xiàn)錯誤,導(dǎo)致無法判斷是否位奇偶檢驗的錯誤,但發(fā)生的概率很低。
下面是對代碼的理解: 可以看出USART_RX_STA類似與一個16位的寄存器,前14位存儲的是數(shù)據(jù),后面兩個分別檢測0X0D和0X0A。 接下里分析:
void uart_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整數(shù)部分
fraction=(temp-mantissa)*16; //得到小數(shù)部分
mantissa《《=4;
mantissa+=fraction;
RCC-》APB2ENR|=1《《2; //使能PORTA口時鐘
RCC-》APB2ENR|=1《《14; //使能串口時鐘
GPIOA-》CRH&=0XFFFFF00F;//IO狀態(tài)設(shè)置
GPIOA-》CRH|=0X000008B0;//IO狀態(tài)設(shè)置
RCC-》APB2RSTR|=1《《14; //復(fù)位串口1
RCC-》APB2RSTR&=~(1《《14);//停止復(fù)位
//波特率設(shè)置
USART1-》BRR=mantissa; // 波特率設(shè)置
USART1-》CR1|=0X200C; //1位停止,無校驗位。
#if EN_USART1_RX //如果使能了接收
//使能接收中斷
USART1-》CR1|=1《《5; //接收緩沖區(qū)非空中斷使能
MY_NVIC_Init(3,3,USART1_IRQn,2);//組2,最低優(yōu)先級
#endif
} temp=(float)(pclk2*1000000)/(bound*16);這是一個計算公式,因為使能的是串口1,而串口1是在APB2ENR寄存器里面(其余串口均在寄存器APB1ENR里面),因為APB2的頻率一般位72M,而APB1的頻率一般位36M。 所以這里的pclk2為72M,而bound是你需要設(shè)置的波特率。
USARTX-BRR: 前四位為小數(shù)部分 ,后12位是整數(shù)部分,假設(shè)算出來的mantissa = 39.5,小數(shù)部分相當(dāng)于把1分成了16份,所以相當(dāng)于把0.5*16轉(zhuǎn)化為二進制存入。
mantissa = temp的作用僅僅是:為了接下來將小數(shù)部分求出來
fraction=(temp-mantissa)*16; //得到小數(shù)部分
mantissa《《=4; 這兩行代碼是為將十進制的整數(shù)部分和小數(shù)部分,分別轉(zhuǎn)化為16進制。然后存入到波特率寄存器里面。緊接著使能串口1和PORTA時鐘(串口一對應(yīng)的IO口是PA9,PA10,需要拿跳帽連接在一起)。 然后將IO口置零,然后分別進行設(shè)置成一個輸入一個輸出,
USART1-》CR1|=0X200C; 設(shè)置成使能串口8個字長1個停止位(USART_CR2中[13:12]默認為“0”)
MY_NVIC_Init(3,3,USART1_IRQn,2)
將其分在組2里面,此時的搶占優(yōu)先級:響應(yīng)優(yōu)先級為 = 2:2,即(00-11)四種情況,而3:3的安排選擇了組2優(yōu)先級最小的一種情況。這樣可以先執(zhí)行上面的波特率賦值,以及串口使能等等操作,最后再進行這行代碼運行。 接下來看下一部分:
u16 USART_RX_STA=0; //接收狀態(tài)標(biāo)記
void USART1_IRQHandler(void)
{
u8 res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
OSIntEnter();
#endif
if(USART1-》SR&(1《《5)) //接收到數(shù)據(jù)
{
res=USART1-》DR;
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0x3fff]=res;
USART_RX_STA++;
if(USART_RX_STA》(USART_REC_LEN-1))USART_RX_STA=0;//接收數(shù)據(jù)錯誤,重新開始接收
}
}
}
} 起始階段: USART_RX_STA=0,對接受狀態(tài)的標(biāo)記。 先通過狀態(tài)寄存器SR的RXNE是否為1,是1則接收到了數(shù)據(jù),反之則沒有。緊接這定義一個res變量來接收從數(shù)據(jù)寄存器的一個字節(jié),然后此時USART_RX_STA為0,與0X8000進行&運算,結(jié)果為0,則未接受到,接著繼續(xù)進行判斷,0X4000進行與運算,看是否為0,也是判斷是否接受道路0X0D,如果沒有接受到,則將這個res變量存放在數(shù)組里面,此時的USART_RX_STA為 0 與0X3fff進行&運算,大家算算會發(fā)現(xiàn),因為他的前14位是數(shù)據(jù)位,所以你會發(fā)現(xiàn)第一個變量就會存放在BUF[0]里面,大概邏輯是這樣的: 所以每個字節(jié)都會被存放到具體的數(shù)組位上 。 if(USART_RX_STA》(USART_REC_LEN-1))USART_RX_STA=0;//接收數(shù)據(jù)錯誤,重新開始接收 當(dāng)數(shù)組越界的時候,則會重新開始。 接下來就會一直循環(huán),當(dāng)數(shù)據(jù)位存滿后,接下來res里面接受的就是0X0D,先和上面一樣判斷USART_RX_STA是否接受到了0X0A和0X0D。 接著執(zhí)行:
if(res==0x0d)USART_RX_STA|=0x4000; 將USART_RX_STA的第十五位變?yōu)?,,接下來進行下一次循環(huán),這一次res接受到的值為0X0A, 然后進行判斷進入到
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
} 所以執(zhí)行USART_RX_STA|=0x8000,使得USART_RX_STA的第十六位變?yōu)?。 接下來看主函數(shù)部分:
int main(void)
{
u8 t;
u8 len;
u16 times=0;
Stm32_Clock_Init(9); //系統(tǒng)時鐘設(shè)置
delay_init(72); //延時初始化
uart_init(72,9600); //串口初始化為9600
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的數(shù)據(jù)長度
printf(“
您發(fā)送的消息為:
”);
for(t=0;t《len;t++)
{
USART1-》DR=USART_RX_BUF[t];
while((USART1-》SR&0X40)==0);//等待發(fā)送結(jié)束
}
printf(“
”);//插入換行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf(“
ALIENTEK MiniSTM32開發(fā)板 串口實驗
”);
printf(“正點原子@ALIENTEK
”);
}
if(times%200==0)printf(“請輸入數(shù)據(jù),以回車鍵結(jié)束
”);
if(times%30==0)LED0=!LED0;//閃爍LED,提示系統(tǒng)正在運行。
delay_ms(10);
} }
} if(USART_RX_STA&0x8000) 判斷是否接收到了0X0A len=USART_RX_STA&0x3fff;舉個簡單的例子此時USART_RX_STA為1100000000000011和0X3fff進行&運算,得到的結(jié)果是3,自然就表示了當(dāng)前數(shù)組的大小。 最后階段,重點理解以下兩行代碼:
USART1-》DR=USART_RX_BUF[t];
while((USART1-》SR&0X40)==0);//等待發(fā)送結(jié)束 分析如下:將每個組內(nèi)的信息存入到數(shù)據(jù)寄存器,此時數(shù)據(jù)寄存器將數(shù)據(jù)給TDR,發(fā)送信息的時候,是一位一位發(fā)送的,每一數(shù)據(jù)幀都有起始位,數(shù)據(jù)位,以及停止位,當(dāng)檢測到數(shù)據(jù)寄存器的細信息發(fā)送完了(完全給了TDR),此時狀態(tài)寄存器的TXE便變?yōu)?,當(dāng)檢測到TXE為1后,TC也會變?yōu)?(系統(tǒng)自動進行)。所以第二行才會檢測這個狀態(tài)寄存器的第6位是否為1來判斷是否發(fā)送成功了這個字節(jié)。 由此推出,直接判斷TXE也可以判斷發(fā)送是否完成 所以代碼可以改為:
for(t=0;t《len;t++)
{
USART1-》DR=USART_RX_BUF[t];
while((USART1-》SR&0X80)==0);//等待發(fā)送結(jié)束
編輯:黃飛
-
寄存器
+關(guān)注
關(guān)注
31文章
5355瀏覽量
120529 -
STM32
+關(guān)注
關(guān)注
2270文章
10904瀏覽量
356363 -
編程
+關(guān)注
關(guān)注
88文章
3619瀏覽量
93781 -
串口
+關(guān)注
關(guān)注
14文章
1555瀏覽量
76587 -
USART
+關(guān)注
關(guān)注
1文章
195瀏覽量
30884
發(fā)布評論請先 登錄
相關(guān)推薦
評論