前言
上一篇中,對串口做了個概述,主要是介紹了串口通信的特征,異步串行全雙工通信,然后就是結合串口的框圖梳理了一下STM32中USART的配置流程以及發(fā)送接收數據的流程,本文將接著上篇的內容,對串口的寄存器做個介紹,然后實現一個簡單的收發(fā)實驗。
USART的相關寄存器介紹
根據之前GPIO的經驗,咱們可以打開中文編程手冊去找到對應的章節(jié),然后依次看一下寄存器的每個位的功能。具體的位置在手冊的第20章。
狀態(tài)寄存器:USARTX->SR
首先第一個寄存器,就是狀態(tài)寄存器,其作用就是用于描述USART的工作狀態(tài),為編程者提供一個串口的實時狀態(tài),前面分析框圖的時候,有提到過,發(fā)送時需要判斷上一幀有沒有發(fā)送完畢;接收時需要判斷一幀數據有沒有接收完畢,當時說的是有內部的標志,這其中的標志就在此寄存器中。
狀態(tài)寄存器是只讀。
寄存器的訪問方式,還是結構體指針指向成員的寫法:
**USARTx->SR(x代表1、2、3、6)
或者
UARTx->SR(x代表4、5)**
具體位代表的含義
-
位 7 TXE:發(fā)送數據寄存器為空 (Transmit data register empty)
用于判斷發(fā)送數據寄存器
當發(fā)送數據寄存器為空 1
當發(fā)送數據寄存器不為空 0
從發(fā)送數據寄存器發(fā)送到移位寄存器 這一位置1 -
位 6 TC:發(fā)送完成 (Transmission complete)
用于判斷上一幀數據是否發(fā)送完成
發(fā)送完成 1
發(fā)送未完成 0
移位寄存器將數據發(fā)送完了,會將這一位置1;用于判斷上一幀有么有發(fā)送完畢,沒有就等待。
參照之前GPIO等待松手的寫法,等待發(fā)送完成的代碼應該是下面這個樣子:
while( !(USART1->SR & 1<<6) ); /如果不為1 則一直等待
- 位 5 RXNE:讀取數據寄存器不為空 (Read data register not empty)
判斷數據接收結束了(接受完畢了CPU就可以將數據讀取到變量)。
如果數據接收結束 1
如果數據沒有接收結束 0 - 位 4 IDLE:檢測到空閑線路 (IDLE line detected)
檢測到空閑線路時,該位由硬件置 1。這位此文用不上,下一篇的串口中斷中會應用到,想要了解可以自己去手冊細看。
剩下的位,包括第0位的奇偶校驗,一般都不做配置,所以在這也不看了。
實際代碼
到這里關于發(fā)送和接收的代碼編寫思路其實已經有了,用串口1為例,代碼如下:
//注意注釋
串口的發(fā)送字符數據函數
{
等待上一幀數據發(fā)送完成
發(fā)送數據
}
/*******************************************
*函數名 :Usart1_Send_Byte
*函數功能 :串口1發(fā)送一個字節(jié)函數
*函數參數 :u8 data
*函數返回值:無
*函數描述 :
發(fā)送一個U8類型的字符
*********************************************/
void Usart1_Send_Byte(u8 data)
{
//等待之前的發(fā)送完成
while(!(USART1->SR & (1<<6)));
//將要發(fā)送的數據給數據寄存器
USART1->DR = data;
}
接收過程
{
等待接收移位寄存器為滿
接收數據
}
/*******************************************
*函數名 :Usart1_Receive_Byte
*函數功能 :串口1接收一個字節(jié)函數
*函數參數 :void
*函數返回值:u8 str
*函數描述 :
發(fā)送一個U8類型的字符
*********************************************/
u8 Usart1_Receive_Byte(void)
{
u8 str;
//等待接收完成
while(!(USART1->SR & (1<<5)));
//將數據寄存器的數據讀取到
str = USART1->DR;
return str;
}
這個寄存器最大作用就是解決了上一篇中發(fā)送完成和接收完成的兩個標志位的問題,完善了框圖中發(fā)送和接收過程的標志判斷問題。
注意上面的代碼中,無論是寫數據還是讀數據都用到了一個USART1->DR的
寄存器,那么它的作用又是什么呢,接下里就對它來做個分析。
數據寄存器 USARTX->DR
注意手冊中紅框的表述,前面的框圖中,發(fā)送和接收是兩個數據寄存器,但實際在單片機內部是一個,這兩個寄存器的唯一區(qū)別方法就是,執(zhí)行寫操作就是發(fā)送數據寄存器(TDR),執(zhí)行讀操作的時候就是接受數據寄存器(RDR)。這也就解釋了為什么上面的代碼中,讀和寫都是使用的DR寄存器。
波特率寄存器 USARTX->BRR
然后就是波特率寄存器,根據昨天的框圖,在波特率的配置過程中,只用將計算的DIV結構寫入一個寄存器即可。如下圖:該寄存器的4-15位就是寫入DIV的整數部分,0-3位就是寫入DIV的小數部分。
至于怎么寫,參照前面的經驗,直接使用賦值語句即可。還是借用昨天的
使用串口1,最后一句就是寫入過程。
波特率:115200 時鐘大小:84000000 過采樣:16
float USARTDIV;
unsigned int DIV_M;
unsigned int DIV_F;
USARTDIV=84000000/16/115200; // 45.57291666666667
DIV_M =(u32) USARTDIV;//讀取整數部分
DIV_F = (USARTDIV- DIV_M)*16+0.5 f //考慮四舍五入
USART1->BRR = DIV_M<<4 | DIV_F;//寫入BRR寄存器
控制寄存器 (USART_CR)
前面三個寄存器已經解決了前面框圖分析提到的發(fā)送接收以及波特率的配置,剩下的USART_CR1、USART_CR2、USART_CR3就是用來配置串口控制器的,可以預見的是,這三個寄存器絕對是與串口的剩下三要素緊密相光的。
控制寄存器1(USART_CR1)
如上圖,控制寄存器1的高十六位是做保留的,只有低十六位用來做配置,這里還是先挑出今天需要使用的位,想要全面了解的可以自己去看數據手冊哈。
-
位 15 OVER8:過采樣模式 (Oversampling mode),過采樣,很熟悉吧,上面一個寄存器中計算公式的8倍過采樣還是16倍過采樣就是通過這個寄存器來進行配置的,寄存器寫1時是8倍過采樣,寫0時是16倍過采樣。
-
位 13 UE:USART 使能 (USART enable)
片上外設使能----模塊級使能
打開時鐘 ----內核級使能
“注?。。。壕邆渑渲脤懕Wo,進行USART配置的時候要先關閉使能,其他的配置完才能打開使能,要放在串口配置的最后一個” -
位 12 M:字長 (Word length)
配置數據位,此位就是用來配置四要素中的數據位的,一般配置為8位數據位,也就是對其寫0。 -
位 10 PCE:奇偶校驗控制使能 (Parity control enable)
一般沒有使用,所以直接配置為0,禁止奇偶校驗。 -
位 3 TE:發(fā)送器使能 (Transmitter enable)
使能發(fā)送器配置為1即可。 -
位 2 RE:接收器使能 (Receiver enable)使能接收。
在控制寄存器1中我們需要操作的就是這些位,這里需要注意寫法,控制寄存器1(USART_CR1),在代碼中的寫法是
USART1->CR[0]
控制寄存器2(USART_CR2)
可以發(fā)現,上面的控制寄存器1配置完后,四要素還有一個沒有配置完畢,那就是停止位的配置,所以關于控制寄存器2,目前唯一用的上的就是第12
和13位。
一般配置為1個停止位,也就是寫入00。
可以發(fā)現,到此,關于框圖中的分析出來的,使能、四要素,發(fā)送,接收都齊活了,可是還有好幾個寄存器沒有露臉啊,這個后面遇到相關功能了再回來看,今天的功能確實只需要使用到上面的這些寄存器就夠了。
關于控制寄存器的具體代碼如下:
/*-----------------------------------------------------------------------*/
//Usart1初始化(四要素)
RCC->APB2ENR |= (1<<4);//打開AHB2上的Usart_1時鐘使能。
/* //CR1
// USART1->CR1 &= ~(1<<15); //16倍過采樣
// USART1->CR1 &= ~(1<<12); //8位字長
// USART1->CR1 &= ~(1<<10); //無奇偶校驗
// USART1->CR1 |= (1<<3); //發(fā)送使能
// USART1->CR1 |= (1<<2); //接收使能*/
USART1->CR1 &=~ (0XB<<12);//清零(16倍過采樣,8位字長)
USART1->CR1 |= (3<<2); //配置CR1寄存器,無奇偶校驗、發(fā)送使能接收使能
//CR2
USART1->CR2 &= ~(3<<12); //1個停止位
/*-----------------------------------------------------------------------*/
//串口使能(最后開啟使能,不然會鎖住寄存器導致配置失敗)
USART1->CR1 |= (1<<13);
可以發(fā)現,到這里關于昨天框圖的流程已經走完了,那么是不是將上面的這些代碼放進工程就可以了呢,事實上是不行的,還漏了一個點,前面介紹GPIO的時候說過,任何需要CPU與外界進行數據交換的時間,都需要使用到GPIO,很明顯,上面的步驟中,還沒有對GPIO進行操作。根據GPIO那篇的介紹,現在這種情況屬于GPIO的復用模式,那么該怎么配置呢,分析如下:
GPIO的復用模式
查詢對應GPIO管腳
既然GPIO是唯一通道,那么串口的通道具體對應那幾個GPIO口呢,根據前面的通信特征可以知道應該會用到兩個GPIO口,一個是TX一個是RX那么具體的對應要怎么查詢呢,在數數據手冊的第三章最后一個表格中有具體的映射,這里還是以USART1來說,首先在上方找到USART1,然后向下找到USART1_TX和USART1_RX然后再向左尋找即可看見對應管腳
,細心的同學肯定會發(fā)現一個問題,在后面的續(xù)表中還有一組GPIO口對應值USART1的TX和RX,這時候到底要配置哪一組呢,解決方法就是看原理圖的物理連接用的是什么。通過原理圖可以發(fā)現使用的是PA9和PA10這一組,所以說,在配置過程中就要使用PA9和PA10管腳。
配置為復用模式
前面的按鍵輸入和控制LED做了通用輸入模式和通用輸出模式的配置,這是第一次使用到復用模式的配置,那么關于復用模式具體怎么配置呢,之前在介紹GPIO的寄存的時候,有兩個寄存器當時給略過了,現在就需要用到他們了,GPIO的復用功能寄存器,其中GPIO復用功能低寄存器對應控制的是0-7八個管腳的復用功能,GPIO復用功能高寄存器對應控制的是8-15這八個管腳的復用功能,這里使用的是PA9和PA10屬于復用功能高位寄存器,這里和上面的串口控制寄存器一樣需要注意寄存器具體的寫法:
GPIO復用功能低位寄存器: GPIOx->AFR[0]
GPIO復用功能高位寄存器: GPIOx->AFR[1]
然后在上面的引腳映射表中可以看見有個AF7,這個AF7就可以讓PA9PA10對應到USART1的TX和RX。注意到編程手冊的描述,對應AF7需要寫入的是0111,也就是說,需要對AFR9和AFR10中寫入0111即可。
具體的配置代碼:
RCC->AHB1ENR |= (1<<0); //打開AHB1上GPIOA端口
GPIOA ->MODER &= ~(0xf<<18);//清0 GPIOA_MODER寄存器
GPIOA ->MODER |= (0xA<<18); //GPIOA_MODER寄存器配置為復用模式
GPIOA->AFR[1] &= ~((15<<4) | (15<<8)); //清零
GPIOA ->AFR[1]|= (0X77<<4); //A9,A10配置為AF7(USART1的TX、RX)
編程實現串口收發(fā)一個字節(jié)
根據上面的介紹,我們將函數進行封裝,串口配置部分就使用初始化函數,接收和發(fā)送就是用功能函數,同樣的,這是一個新模塊,還是需要新建兩個文件用來存放源文件和頭文件。
具體的代碼:
#include "Usart1.h"
/*******************************************
*函數名 :Usart1_Init
*函數功能 :串口1初始化函數
*函數參數 :u32 bps波特率
*函數返回值:無
*函數描述 :
PA9--------USART1_TX
PA10-------USART1_RX
*********************************************/
void Usart1_Init(u32 bps)
{
float USARTDIV;
unsigned int DIV_M;
unsigned int DIV_F;
//GPIOA9、GPIOA10的初始化
RCC->AHB1ENR |= (1<<0); //打開AHB1上GPIOA端口
GPIOA ->MODER &= ~(0xf<<18);//清0 GPIOA_MODER寄存器
GPIOA ->MODER |= (0xA<<18); //GPIOA_MODER寄存器配置為復用模式
GPIOA->AFR[1] &= ~((15<<4) | (15<<8)); //清零
GPIOA ->AFR[1]|= (0X77<<4); //A9,A10配置為AF7(USART1的TX、RX)
/*-----------------------------------------------------------------------*/
//Usart1初始化(四要素)
RCC->APB2ENR |= (1<<4);//打開AHB2上的Usart_1時鐘使能。
//以下是兩種配置方式,注釋部分是一位一位的配置,未注釋的是一起配置的部分。
/* //CR1
// USART1->CR1 &= ~(1<<15); //16倍過采樣
// USART1->CR1 &= ~(1<<12); //8位字長
// USART1->CR1 &= ~(1<<10); //無奇偶校驗
// USART1->CR1 |= (1<<3); //發(fā)送使能
// USART1->CR1 |= (1<<2); //接收使能*/
USART1->CR1 &=~ (0XB<<12);//清零(16倍過采樣,8位字長)
USART1->CR1 |= (3<<2); //配置CR1寄存器,無奇偶校驗、發(fā)送使能接收使能
//CR2
USART1->CR2 &= ~(3<<12); //1個停止位
/*-----------------------------------------------------------------------*/
//BRR波特率計算
USARTDIV = 84000000/16/bps; //
DIV_M =(u32)USARTDIV;
DIV_F = (USARTDIV - DIV_M)*16+0.5f; //考慮四舍五入
USART1->BRR = DIV_M<<4 | DIV_F;
/*-----------------------------------------------------------------------*/
//串口使能(最后開啟使能,不然會鎖住寄存器導致配置失?。?/span>
USART1->CR1 |= (1<<13);
}
//?。?!還需要將上面的發(fā)送一個字節(jié)和接收一個字節(jié)函數添加進來?。。。。?/span>
#ifndef _USART1_H__
#define _USART1_H_
#include "stm32f4xx.h"
void Usart1_Init(u32 bps);
void Usart1_Send_Byte(u8 data);
u8 Usart1_Receive_Byte(void);
#endif
然后在主函數調用初始化,編譯
串口打印亂碼
編譯下載后發(fā)現,并沒有按照我們的代碼寫的發(fā)送出‘A’到串口調試助手上,而是問號,仔細檢查發(fā)現配置也沒有問題,而且再林外一塊板子上可以使用,那這是為什么呢。
后來,經過檢查,是因為官方的時鐘配置文件的分配是以25MHZ的晶振為基礎來寫的,而我的板子是8M晶振,造成了時序混亂,所以打印亂碼了,修改為8后就可以了。
修改后,可以正常打印字符A了。
接收一個字符
需求1:使用PC機控制板子的LED燈
接收字符 ’O’ 打開全部燈
接收字符‘F’關閉全部燈
答:直接調用前面的接收函數,然后判斷接受到的值,執(zhí)行操作即可。
運行效果
文章來源:http://www.zghlxwxcb.cn/news/detail-445704.html
M4系列目錄
1.嵌入式學習筆記——概述
2.嵌入式學習筆記——基于Cortex-M的單片機介紹
3.嵌入式學習筆記——STM32單片機開發(fā)前的準備
4.嵌入式學習筆記——STM32硬件基礎知識
5.嵌入式學習筆記——認識STM32的 GPIO口
6.嵌入式學習筆記——使用寄存器編程操作GPIO
7.嵌入式學習筆記——寄存器實現控制LED小燈
8.嵌入式學習筆記——使用寄存器編程實現按鍵輸入功能
9.嵌入式學習筆記——STM32的USART通信概述
10.嵌入式學習筆記——STM32的USART相關寄存器介紹及其配置
11.嵌入式學習筆記——STM32的USART收發(fā)字符串及串口中斷
12.嵌入式學習筆記——STM32的中斷控制體系
13.嵌入式學習筆記——STM32寄存器編程實現外部中斷
14.嵌入式學習筆記——STM32的時鐘樹
15.嵌入式學習筆記——SysTick(系統(tǒng)滴答)
16.嵌入式學習筆記——M4的基本定時器
17.嵌入式學習筆記——通用定時器
18.嵌入式學習筆記——PWM與輸入捕獲(上)
19.嵌入式學習筆記——PWM與輸入捕獲(下)
20.嵌入式學習筆記——ADC模數轉換器
21.嵌入式學習筆記——DMA
22.嵌入式學習筆記——SPI通信
23.嵌入式學習筆記——SPI通信的應用
24嵌入式學習筆記——IIC通信文章來源地址http://www.zghlxwxcb.cn/news/detail-445704.html
到了這里,關于嵌入式學習筆記——STM32的USART相關寄存器介紹及其配置的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!