之前買了一塊評估板,也寫了相應的評測文章,鏈接如下:
TKM32F499高性能MCU評估板試用之萬事開頭難,先點個燈來壓壓驚!
我們在上面這篇文章已經(jīng)領會了TKM32F499的強大了,接下來進入主題,串口通信實驗。
1、TKM32F499通用異步收發(fā)器(UART)數(shù)據(jù)結構及參數(shù)描述
在UART庫的頭文件里,UART由一個結構體進行維護:
typedef struct
{
//波特率
uint32_t UART_BaudRate;
//數(shù)據(jù)長度
uint16_t UART_WordLength;
//停止位
uint16_t UART_StopBits;
//校驗位
uint16_t UART_Parity;
//模式
uint16_t UART_Mode;
//硬件流控
uint16_t UART_HardwareFlowControl;
} UART_InitTypeDef;
1.1 波特率
波特率是由波特率發(fā)生器產(chǎn)生的,這是一個專用16位的,UART波特率寄存器控制16 位自由運轉(zhuǎn)的計數(shù)器的計數(shù)周期。提供期望的波特率和 Fosc(APB 時鐘頻率)
X = SPBRG 寄存器值 (1 to 65535)
1.2 數(shù)據(jù)長度
/** @defgroup UART_Word_Length
* @{
*/
#define UART_WordLength_5b ((uint16_t)0x0000)
#define UART_WordLength_6b ((uint16_t)0x0010)
#define UART_WordLength_7b ((uint16_t)0x0020)
#define UART_WordLength_8b ((uint16_t)0x0030)
一般在工程應用中都是選擇UART_WordLength_8b
1.3 停止位
/** @defgroup UART_Stop_Bits
* @{
*/
#define UART_StopBits_1 ((uint16_t)0x0000)
#define UART_StopBits_2 ((uint16_t)0x0004)
#define IS_UART_STOPBITS(STOPBITS) (((STOPBITS) == UART_StopBits_1) || \
((STOPBITS) == UART_StopBits_2))
一般在工程應用中都是選擇UART_StopBits_1
1.4 校驗位
/** @defgroup UART_Parity
* @{
*/
#define UART_Parity_No ((uint16_t)0x0000)
#define UART_Parity_Even ((uint16_t)0x0003)
#define UART_Parity_Odd ((uint16_t)0x0001)
#define IS_UART_PARITY(PARITY) (((PARITY) == UART_Parity_No) || \
((PARITY) == UART_Parity_Even) || \
((PARITY) == UART_Parity_Odd))
一般在工程應用中都是選擇UART_Parity_No(無校驗)
1.5 串口模式
/** @defgroup UART_Mode
* @{
*/
#define UART_Mode_Rx ((uint16_t)0x0008)
#define UART_Mode_Tx ((uint16_t)0x0010)
#define IS_UART_MODE(MODE) ((((MODE) & (uint16_t)0xFFE7) == 0x00) && ((MODE) != (uint16_t)0x00))
這個指的是當前串口為可接收還是可發(fā)送,可以同時擁有,也可以單個選擇,具體根據(jù)項目需求制定。
1.6 硬件流控
/** @defgroup UART_Hardware_Flow_Control
* @{
*/
#define UART_HardwareFlowControl_None ((uint16_t)0x0000)
#define IS_UART_HARDWARE_FLOW_CONTROL(CONTROL)\
(((CONTROL) == UART_HardwareFlowControl_None) || \
((CONTROL) == UART_HardwareFlowControl_RTS) || \
((CONTROL) == UART_HardwareFlowControl_CTS) || \
((CONTROL) == UART_HardwareFlowControl_RTS_CTS))
一般工程應用中會直接將這個設置為UART_HardwareFlowControl_None 在HAL_uart.h庫文件中提供了一系列操作接口:
void UART_DeInit(UART_TypeDef* UARTx);
void UART_Init(UART_TypeDef* UARTx, UART_InitTypeDef* UART_InitStruct);
void UART_StructInit(UART_InitTypeDef* UART_InitStruct);
void UART_Cmd(UART_TypeDef* UARTx, FunctionalState NewState);
void UART_ITConfig(UART_TypeDef* UARTx, uint16_t UART_IT, FunctionalState NewState);
void UART_DMACmd(UART_TypeDef* UARTx, uint16_t UART_DMAReq, FunctionalState NewState);
void UART_SendData(UART_TypeDef* UARTx, uint16_t Data);
uint16_t UART_ReceiveData(UART_TypeDef* UARTx);
FlagStatus UART_GetFlagStatus(UART_TypeDef* UARTx, uint16_t UART_FLAG);
void UART_ClearFlag(UART_TypeDef* UARTx, uint16_t UART_FLAG);
ITStatus UART_GetITStatus(UART_TypeDef* UARTx, uint16_t UART_IT);
void UART_ClearITPendingBit(UART_TypeDef* UARTx, uint16_t UART_IT);
跟STM32操作類似,我們直接調(diào)就完了,不明白的地方直接看數(shù)據(jù)手冊解決!
2、TKM32F499通用異步收發(fā)器(UART)使用
使用串口功能之前,還是一樣,先確定我這邊的需求,我這邊需要接收一串以下格式的數(shù)據(jù):
序號 信號值 差值\r\n
這個數(shù)據(jù)是我手上傳感器發(fā)過來的數(shù)據(jù),然后我用TKM32F499進行接收。
1、配置一路串口用于printf輸出,這里選擇UART4
電路原理圖如下:
根據(jù)原理圖寫出以下初始化函數(shù):
/*用于調(diào)試打印*/
void Uart4Init(int BaudRate)
{
UART_InitTypeDef UART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復用推挽輸出
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_Pin_6 | GPIO_Pin_7, GPIO_AF_UART_2345);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART4, ENABLE);
UART_InitStructure.UART_BaudRate = BaudRate; //波特率
UART_InitStructure.UART_WordLength = UART_WordLength_8b;//數(shù)據(jù)位
UART_InitStructure.UART_StopBits = UART_StopBits_1;//停止位
UART_InitStructure.UART_Parity = UART_Parity_No ;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;//輸入輸出模式
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_Init(UART4, &UART_InitStructure);
UART_Cmd(UART4, ENABLE); //UART 模塊使能
UART_ClearITPendingBit(UART4, 0xff);
}
調(diào)試不用增加接收功能,所以不需要寫接收回調(diào)函數(shù),但需要寫一個串口重定向,并把微庫勾上才能使用printf。
編寫重定向函數(shù):
int fputc(int ch, FILE *f)
{
while((UART4->CSR & 0x1) == 0) {}
UART4->TDR = (u8) ch;
return ch;
}
2、配置一路串口用于接收傳感器數(shù)據(jù)(這里選擇接UART1)
電路原理圖如下:
實現(xiàn)代碼邏輯:
/*用于接收傳感器數(shù)據(jù)*/
void Uart1Init(int BaudRate)
{
UART_InitTypeDef UART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //uart1_tx pa9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 推挽復用輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //uart1_rx pa10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_Pin_9 | GPIO_Pin_10, GPIO_AF_UART_1); //PA9、PA10復用為串口1
GPIO_PinAFConfig(GPIOA, GPIO_Pin_15, GPIO_AF_GPIO); //PA15復用為普通GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_UART1, ENABLE);
UART_InitStructure.UART_BaudRate = BaudRate; //波特率
UART_InitStructure.UART_WordLength = UART_WordLength_8b;//數(shù)據(jù)位
UART_InitStructure.UART_StopBits = UART_StopBits_1;//停止位
UART_InitStructure.UART_Parity = UART_Parity_No ;
UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;//輸入輸出模式
UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
UART_Init(UART1, &UART_InitStructure);
UART_Cmd(UART1, ENABLE); //UART 模塊使能
UART_ClearITPendingBit(UART1, 0xff);
//這里需要進行接收,所以要打開接收中斷
UART_ITConfig(UART1, UART_IT_RXIEN, ENABLE);//使能接收中斷
NVIC_SetPriority(UART1_IRQn, 3);
NVIC_EnableIRQ(UART1_IRQn);
}
定義回調(diào)函數(shù),編寫接收邏輯,傳感器用一個結構體進行維護:
#define SENSOR_BUFFER_SIZE 42
typedef struct
{
uint8_t BufferReady;
uint16_t Sensor_rx_count ;
uint8_t SensorRxBuffer[SENSOR_BUFFER_SIZE];
uint8_t SensorTxBuffer[SENSOR_BUFFER_SIZE];
} Sensor_HandleTypeDef;
extern Sensor_HandleTypeDef Sensor;
接收回調(diào)函數(shù)處理:
//串口1接收中斷處理函數(shù),打印傳感器數(shù)據(jù)
void UART1_IRQHandler(void)
{
u8 ucCh;
/*當ISR位1為1時,表示接收到有效字節(jié)數(shù)據(jù)*/
if(UART1->ISR & (1 << 1))
{
/*接收到了一個字節(jié)的數(shù)據(jù)*/
ucCh = UART1->RDR;
if('\n' != ucCh)
{
Sensor.SensorRxBuffer[Sensor.Sensor_rx_count++] = ucCh ;
}
else
{
/*如果接收的是\n,則上一個接收的數(shù)據(jù)為'\r'結束*/
if('\r' == Sensor.SensorRxBuffer[Sensor.Sensor_rx_count - 1])
{
/*添加結束符*/
Sensor.SensorRxBuffer[Sensor.Sensor_rx_count - 1] = 0x00 ;
/*接收計數(shù)清0*/
Sensor.Sensor_rx_count = 0 ;
Sensor.BufferReady = 1 ;
}
}
/*清除中斷接收標志*/
UART1->ICR |= 1 << 1;
}
}
接收這里主要用到串口的接收數(shù)據(jù)寄存器、中斷狀態(tài)寄存器、中斷清除寄存器
接收數(shù)據(jù)在程序里就是一個RDR的寄存器。其中在接收邏輯里需要去判斷接收數(shù)據(jù)有效,最重要的是位1:
在每次收到一次有效數(shù)據(jù),即發(fā)生了一次串口接收中斷,我們接收完數(shù)據(jù)后需要及時對中斷標志進行清除,這里最重要的是第一位:這些寄存器都是通過一個結構體進行維護:
/**
* @brief Universal Synchronous Asynchronous Receiver Transmitter
*/
typedef struct
{
__IO uint32_t TDR;
__IO uint32_t RDR;
__IO uint32_t CSR;
__IO uint32_t ISR;
__IO uint32_t IER;
__IO uint32_t ICR;
__IO uint32_t GCR;
__IO uint32_t CCR;
__IO uint32_t BRR;
__IO uint32_t FRABRG;
} UART_TypeDef;
具體使用方法請參考TKM32F499的芯片數(shù)據(jù)手冊,當然如果不習慣用寄存器進行操作,也可以使用好炬潤官方的HAL lib,調(diào)用相應的庫函數(shù)。串口應用邏輯編寫完畢以后,接下來我們在主函數(shù)的循環(huán)內(nèi)判斷BufferReady標志就可以了:
while(1)
{
if(1 == Sensor.BufferReady)
{
Sensor.BufferReady = 0;
/*解析傳感器數(shù)據(jù)*/
Sensor_Detect_Process(Sensor.SensorRxBuffer);
printf("流水號:%d 信號值:%d 差值:%d\n",sensor_data.Sensor_Serial_Number
,sensor_data.Sensor_TP1_Singal_Value,sensor_data.Sensor_TP1_Devalue
);
LCD_PutString(100, 60, (char *)Sensor.SensorRxBuffer, Red, Yellow, 1);
status = !status;
GPIO_WriteBit(GPIOA,GPIO_Pin_15,status);
}
}
最終效果,這里面還有我的其它邏輯:
如果對該評估板軟件編程感興趣的話,歡迎加我微信私聊交流~
TKM32F499評估板例程及資料下載
鏈接:https://pan.baidu.com/s/1xujEO4vJ7i7UUK7v_fGNgw
提取碼:g1y2
或者后臺回復TK499即可獲取。
往期精彩
bin文件轉(zhuǎn)換為hex文件C語言實現(xiàn)
最近收集的開源項目專欄(持續(xù)更新,收好車輪,方便造車)
推薦三個我工作中經(jīng)常使用的驅(qū)動大全wiki(建議收藏并轉(zhuǎn)發(fā)讓更多人知道!)
變量命名還在谷歌百度翻譯?OUT啦!分享一個我日常工作中常用的變量命名神器!
若覺得本次分享的文章對您有幫助,隨手點[在看]
并轉(zhuǎn)發(fā)分享,也是對我的支持。
免責聲明:本文內(nèi)容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!