介紹
串口(UART通用異步收發(fā)器,TTL)通訊是一種設(shè)備間的串行全雙工通訊方式。由于UART是異步傳輸,沒有傳輸同步時(shí)鐘,為了保證數(shù)據(jù)的正確性,UART采用16倍數(shù)據(jù)波特率的時(shí)鐘進(jìn)行采樣。因?yàn)樗啽憬?,因此大部?a target="_blank">電子設(shè)備都支持該通訊方式工程師在調(diào)試設(shè)備時(shí)也經(jīng)常使用該方式輸出調(diào)試信息。
本文詳細(xì)的介紹如何來編寫一個(gè)串口收發(fā)程序,我們采用常用的收發(fā)邏輯,發(fā)送直接編寫函數(shù)進(jìn)行實(shí)現(xiàn),而接收使用中斷進(jìn)行完成。接收中斷使用接收到一個(gè)字節(jié)和一幀數(shù)據(jù)兩種中斷觸發(fā)方式。
USART中斷
USART 有多個(gè)中斷請(qǐng)求事件。
之所以介紹這個(gè)USART中斷請(qǐng)求,是因?yàn)楹芏嗳嗽诔鯇W(xué)階段,對(duì)串口怎么判斷串口中斷的狀態(tài)不太了解,所以我這里重點(diǎn)來介紹一下。
一般在我們開始和配置完串口中斷后,進(jìn)入串口中斷處理程序的情況會(huì)有很多,我們也可以自己選擇打開哪些串口中斷情況。一般情況下,我們在接受時(shí)主要使用的中斷事件標(biāo)志是RXNE和IDLE。
RXNE是接收中斷,每接收一個(gè)字節(jié)都會(huì)出發(fā)這個(gè)中斷,也是我們用的最頻繁的中斷請(qǐng)求。
IDLE 是空閑中斷,每接收完一幀數(shù)據(jù),總線就會(huì)暫時(shí)空閑,就會(huì)觸發(fā)這個(gè)中斷。
串口狀態(tài)
串口的狀態(tài)可以通過狀態(tài)寄存器 USART_SR 讀取。USART_SR 的各位描述如下:
這里我們關(guān)注一下兩個(gè)位,第 5、6 位 RXNE 和 TC。
RXNE(讀數(shù)據(jù)寄存器非空),當(dāng)該位被置 1 的時(shí)候,就是提示已經(jīng)有數(shù)據(jù)被接收到了,且可以讀出來了。這時(shí)候我們要做的就是盡快去讀取 USART_DR,通過讀 USART_DR 可以該位清零,也可以向該位寫 0,直接清除。
TC(發(fā)送完成),當(dāng)該位被置位的時(shí)候,表示 USART_DR 內(nèi)的數(shù)據(jù)已經(jīng)被發(fā)送完成了。果設(shè)置了這個(gè)位的中斷,則會(huì)產(chǎn)生中斷。該位也有兩種清零方式:
- 讀 USART_SR,USART_DR。
- 直接向該位寫 0。
實(shí)例
需求分析
本項(xiàng)目主要編寫一個(gè)串口收發(fā)的實(shí)例。使用STM32F103C8T6充當(dāng)MCU,在PC上使用串口調(diào)試助手充當(dāng)上位機(jī)。每次PC向MCU下發(fā)一幀數(shù)據(jù), MCU每接收一個(gè)字節(jié)數(shù)據(jù),檢查一下數(shù)據(jù)中是否有指令0x23,當(dāng)接收到指令0x23的時(shí)候,MCU向上位機(jī)發(fā)送“PC”。當(dāng)一幀數(shù)據(jù)接收完畢后,MCU向上位機(jī)發(fā)送“Receive a frame data”.
串口初始化
串口初始化的一般步驟可以總結(jié)為如下幾個(gè)步驟:
- 串口時(shí)鐘使能,GPIO 時(shí)鐘使能。
- 設(shè)置引腳復(fù)用器映射:調(diào)用 GPIO_PinAFConfig 函數(shù)。
- GPIO 初始化設(shè)置:要設(shè)置模式為復(fù)用功能。
- 串口參數(shù)初始化:設(shè)置波特率,字長,奇偶校驗(yàn)等參數(shù)。
- 開啟中斷并且初始化 NVIC,使能中斷(如果需要開啟中斷才需要這個(gè)步驟)。
- 使能串口。
#include "usart.h"
#include
#include "stm32f1xx_hal.h
UART_HandleTypeDef huart3
void MX_USART3_UART_Init(void)
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler()
__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中斷使能
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空閑中斷使能
}
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(uartHandle->Instance==USART3)
{
__HAL_RCC_USART3_CLK_ENABLE()
__HAL_RCC_GPIOB_CLK_ENABLE();
/**USART3 GPIO Configuration
PB10 ------> USART3_TX
PB11 ------> USART3_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct)
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_NVIC_SetPriority(USART3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
我們平時(shí)需要改的其實(shí)就是串口的一些參數(shù)配置。
- BaudRate:波特率
- WordLength;:字長
- StopBits:停止位
- Parity:奇偶校驗(yàn)
- Mode:收/發(fā)模式設(shè)置
- HwFlowCtl:硬件流設(shè)置
- OverSampling:過采樣設(shè)置
串口發(fā)送
串口發(fā)送這里使用的非中斷發(fā)送方式。
/*******************************************************************************
* @函數(shù)名稱 USART_Send
* @函數(shù)說明 發(fā)送信息
* @輸入?yún)?shù) _UART:串口號(hào)
data:要發(fā)送的信息的首地址
len:發(fā)送的長度
* @輸出參數(shù) 無
* @返回參數(shù) 無
*******************************************************************************/
void USART_Send(USART_TypeDef *_UART,uint8_t *data,uint8_t len)
{
for(int i;i
主要使用的是HAL_UART_Transmit(&huart3,&Res,1,0Xffff);
這是一個(gè)阻塞的發(fā)送函數(shù),無需重復(fù)判斷串口是否發(fā)送完成。發(fā)送每個(gè)字符,直到遇空字符才停止發(fā)送。其中第一個(gè)參數(shù)是串口號(hào),第二個(gè)參數(shù)是要發(fā)送的數(shù)據(jù)起始地址,第三個(gè)是要發(fā)送的數(shù)據(jù)長度,第四個(gè)超時(shí)時(shí)間(超過此長度仍未發(fā)送成功則阻塞完畢,停止發(fā)送,函數(shù)執(zhí)行完畢)。
串口接收
這里串口接收使用的是中斷的方式。
中斷的類別在文章的最上邊已經(jīng)介紹過。我們在初始化時(shí)設(shè)定觸發(fā)中斷的類型。本文中設(shè)置的
__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);//接收中斷使能
__HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);//空閑中斷使能
代表只有接收數(shù)據(jù)和空閑中斷會(huì)觸發(fā)。
在stm32f1xx_it.c中有我們的串口中斷處理函數(shù)。我們將這個(gè)函數(shù)進(jìn)行重構(gòu)。
void USART3_IRQHandler(void)
{
uint8_t Res;
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET
{
HAL_UART_Receive(&huart3,&Res,1,0Xffff);
if(Res==0x23)
printf("PC");
}
else if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)//空閑中斷(代表這一幀數(shù)據(jù)傳輸完了)
{
printf("Receive a frame data.");
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
}
這里面的幾個(gè)重點(diǎn),我們來一一介紹。
首先是判斷標(biāo)志位,我們使用HAL庫中的__HAL_UART_GET_FLAG()函數(shù),里面有兩個(gè)參數(shù),前者是串口句柄,后者是具體哪個(gè)標(biāo)志位。
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE)!=RESET)用來檢測是否檢測到有單個(gè)字節(jié)的中斷。
if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE)!=RESET)用來檢測是否有空閑中斷(代表這一幀數(shù)據(jù)傳輸完了)。
重定向printf和scanf
還有一點(diǎn)需要注意的,使用 fput 和 fgetc 函數(shù)達(dá)到重定向 C 語言標(biāo)準(zhǔn)庫輸入輸出函數(shù)必須在 MDK 的工程選項(xiàng)把“Use MicroLIB”勾選上, MicoroLIB 是缺省 C 庫的備選庫,它對(duì)標(biāo)準(zhǔn) C 庫進(jìn)行了高度優(yōu)化使代碼更少,占用更少資源
為使用 printf、 scanf 函數(shù)需要在文件中包含 stdio.h 頭文件。
/**
* 函數(shù)功能: 重定向c庫函數(shù)printf
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明:無
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函數(shù)功能: 重定向c庫函數(shù)getchar,scanf
* 輸入?yún)?shù): 無
* 返 回 值: 無
* 說 明:無
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart3, &ch, 1, 0xffff);
return ch;
}
效果
-
PC下發(fā):11 22 33 44
-
PC下發(fā):12 23 34 45
-
收發(fā)器
+關(guān)注
關(guān)注
10文章
3462瀏覽量
106272 -
串口
+關(guān)注
關(guān)注
14文章
1559瀏覽量
77124 -
uart
+關(guān)注
關(guān)注
22文章
1244瀏覽量
101804
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
【紫光同創(chuàng)國產(chǎn)FPGA教程】【第五章】串口收發(fā)實(shí)驗(yàn)
![【紫光同創(chuàng)國產(chǎn)FPGA教程】【第五章】<b class='flag-5'>串口</b><b class='flag-5'>收發(fā)</b>實(shí)驗(yàn)](https://file.elecfans.com//web1/M00/DE/65/pIYBAGAY4eeADCSsAAB2rq6b7Ek854.jpg)
編寫第一個(gè)QT程序
如何去編寫一種基于Atmega8單片機(jī)的串口收發(fā)程序?
怎樣去編寫一個(gè)串口數(shù)據(jù)接收程序呢
分享一個(gè)串口收發(fā)的小程序功能
VHDL設(shè)計(jì)的串口通信程序
如何使用Python編寫一個(gè)簡單的程序
verilog編寫UART串口程序下載
![verilog<b class='flag-5'>編寫</b>UART<b class='flag-5'>串口</b><b class='flag-5'>程序</b>下載](https://file.elecfans.com/web1/M00/D5/A6/o4YBAF_gc9mAOhYhAAAN7CbUGdY860.png)
評(píng)論