目錄
一、stm32串口配置
三、串口驅(qū)動(dòng)功能調(diào)用及編譯實(shí)現(xiàn)
四、編譯測(cè)試
??????? 關(guān)于cubeIDE開發(fā)基本技巧及流程,本文不詳細(xì)敘述,請(qǐng)參考:cubeIDE快速開發(fā)流程_py_free的博客-CSDN博客_cubeide漢化
一、stm32串口配置
??????? 本文采用的開發(fā)板是stm32L496VGT3,其有兩個(gè) USB 接口,一個(gè)為 USB ST-link 復(fù)用接口,作用為軟件下載/調(diào)試/ 系統(tǒng)供電輸入口。另一個(gè)為 USB OTG,用戶可以外接 USB 設(shè)備,支持 1000mA,USB2.0 設(shè)備接入。本文就采用 USB ST-link口實(shí)現(xiàn)串口上下行通信及調(diào)試信息輸出顯示。
????????USB ST-Link(USB1) 接口的串口通信及調(diào)試信息需要我們映射實(shí)現(xiàn)。
?????????打開cubeMX配置界面,配置串口映射,開啟LPUART串口或其他USART*(1)的異步傳輸模式(2),配置串口參數(shù)(3),并將串口收發(fā)數(shù)據(jù)端口映射到PB10、PB11上(4),并開啟中斷功能(5),最后點(diǎn)擊保存或生成代碼按鈕生成代碼。
????????開啟外部中斷:
????????設(shè)置上拉輸出:
? 二、串口驅(qū)動(dòng)設(shè)計(jì)及代碼實(shí)現(xiàn)
??????? 重新構(gòu)建系統(tǒng)的printf函數(shù),將其映射到LPUART串口。
????????【1】首先禁用CubeIDE生成syscall.c文件
?????????【2】創(chuàng)建print.h和print.c兩個(gè)驅(qū)動(dòng)文件來取代syscall.c內(nèi)的函數(shù)_read、_write等實(shí)現(xiàn),本文是將這兩個(gè)文件放置在ICore目錄內(nèi)
?????????print.h內(nèi)容如下:
/*
* print.h
*
* Created on: 2021年11月16日
* Author: Administrator
*/
#ifndef INC_RETARGET_H_
#define INC_RETARGET_H_
#include "stm32l4xx_hal.h"
#include "stdio.h"http://用于printf函數(shù)串口重映射
#include <sys/stat.h>
void ResetPrintInit(UART_HandleTypeDef *huart);//將printf()函數(shù)映射到指定串口上
int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char* ptr, int len);
int _fstat(int fd, struct stat* st);
#endif /* INC_RETARGET_H_ */
????????print.c內(nèi)容如下,主要是將syscall.c內(nèi)的空實(shí)現(xiàn)函數(shù)通過串口實(shí)現(xiàn)數(shù)據(jù)收發(fā)處理
/*
* print.c
*
* Created on: 2021年11月16日
* Author: Administrator
*/
#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include "print.h"
#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
UART_HandleTypeDef *gHuart;
void ResetPrintInit(UART_HandleTypeDef *huart) {
gHuart = huart;
/* Disable I/O buffering for STDOUT stream, so that
* chars are sent out as soon as they are printed. */
setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd) {
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 1;
errno = EBADF;
return 0;
}
int _write(int fd, char* ptr, int len) {
HAL_StatusTypeDef hstatus;
if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
//串口發(fā)送數(shù)據(jù)實(shí)現(xiàn),可以main.c等功能代碼中直接調(diào)用HAL_UART_Transmit也能實(shí)現(xiàn)串口發(fā)送數(shù)據(jù)
hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return len;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _close(int fd) {
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 0;
errno = EBADF;
return -1;
}
int _lseek(int fd, int ptr, int dir) {
(void) fd;
(void) ptr;
(void) dir;
errno = EBADF;
return -1;
}
int _read(int fd, char* ptr, int len) {
HAL_StatusTypeDef hstatus;
if (fd == STDIN_FILENO) {
hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return 1;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _fstat(int fd, struct stat* st) {
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
st->st_mode = S_IFCHR;
return 0;
}
errno = EBADF;
return 0;
}
#endif //#if !defined(OS_USE_SEMIHOSTING)
????????【3】創(chuàng)建串口驅(qū)動(dòng)接口,主要就是實(shí)現(xiàn)串口回調(diào)函數(shù)
??????? 前面print.h/c實(shí)現(xiàn)串口輸出能力,但其輸入能力由于lpusart開啟了外部中斷功能,還需我們實(shí)現(xiàn)其回調(diào)函數(shù),因?yàn)閏ubeMX生成的HAL庫(kù)(stm32l4xx_hal_uart.c,文件名因芯片不同有所區(qū)別)的串口接收回調(diào)函數(shù)是個(gè)弱聲明函數(shù),其實(shí)現(xiàn)源碼沒有做什么事。
?????????現(xiàn)在創(chuàng)建usart.h、usart.c兩個(gè)串口驅(qū)動(dòng)文件,放置ICore目錄下
????????usart.h內(nèi)容如下,HAL_UART_RxCpltCallback會(huì)覆蓋stm32l4xx_hal_uart.c的同名回調(diào)函數(shù):
/*
* usart.h
*
* Created on: Oct 20, 2022
* Author: Administrator
*/
#ifndef INC_USART_H_
#define INC_USART_H_
#include "stm32l4xx_hal.h" //HAL庫(kù)文件聲明
#include <string.h>//用于字符串處理的庫(kù)
#include "print.h"http://用于printf函數(shù)串口重映射
extern UART_HandleTypeDef hlpuart1;//聲明USART1的HAL庫(kù)結(jié)構(gòu)體
#define HLPUSART_REC_LEN 256//定義USART1最大接收字節(jié)數(shù)
extern uint8_t HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收緩沖,最大HLPUSART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符
extern uint16_t HLPUSART_RX_STA;//接收狀態(tài)標(biāo)記
extern uint8_t HLPUSART_NewData;//當(dāng)前串口中斷接收的1個(gè)字節(jié)數(shù)據(jù)的緩存
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//串口中斷回調(diào)函數(shù)聲明
#endif /* INC_USART_H_ */
????????usart.c內(nèi)容如下:
/*
* usart.c
*
* Created on: Oct 20, 2022
* Author: Administrator
*/
#include "usart.h"
uint8_t HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收緩沖,最大HLPUSART_REC_LEN個(gè)字節(jié).末字節(jié)為換行符
/*
* bit15:接收到回車(0x0d)時(shí)設(shè)置HLPUSART_RX_STA|=0x8000;
* bit14:接收溢出標(biāo)志,數(shù)據(jù)超出緩存長(zhǎng)度時(shí),設(shè)置HLPUSART_RX_STA|=0x4000;
* bit13:預(yù)留
* bit12:預(yù)留
* bit11~0:接收到的有效字節(jié)數(shù)目(0~4095)
*/
uint16_t HLPUSART_RX_STA=0;接收狀態(tài)標(biāo)記//bit15:接收完成標(biāo)志,bit14:接收到回車(0x0d),bit13~0:接收到的有效字節(jié)數(shù)目
uint8_t HLPUSART_NewData;//當(dāng)前串口中斷接收的1個(gè)字節(jié)數(shù)據(jù)的緩存
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口中斷回調(diào)函數(shù)
{
if(huart ==&hlpuart1)//判斷中斷來源(串口1:USB轉(zhuǎn)串口)
{
if(HLPUSART_RX_STA&0x4000){//溢出,重新開始
HLPUSART_RX_STA=0;//接收錯(cuò)誤,重新開始
}
if(HLPUSART_NewData==0x0d){//回車標(biāo)記
printf("getdata:%.*s \r\n", HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
HLPUSART_RX_STA|=0x8000;//標(biāo)記接到回車
}else{
if((HLPUSART_RX_STA&0X0FFF)<HLPUSART_REC_LEN){
HLPUSART_RX_BUF[HLPUSART_RX_STA&0X0FFF]=HLPUSART_NewData; //將收到的數(shù)據(jù)放入數(shù)組
HLPUSART_RX_STA++; //數(shù)據(jù)長(zhǎng)度計(jì)數(shù)加1
}else{
HLPUSART_RX_STA|=0x4000;//數(shù)據(jù)超出緩存長(zhǎng)度,標(biāo)記溢出
}
}
HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData,1); //再開啟接收中斷
}
}
三、串口驅(qū)動(dòng)功能調(diào)用及編譯實(shí)現(xiàn)
??????? 在原來的key.h/key.c中添加按鍵按下識(shí)別函數(shù),
??????? key.h:
/*
* key.h
*
* Created on: Sep 29, 2022
* Author: py_hp
*/
#ifndef KEY_H_
#define KEY_H_
#include "main.h"
#include "gpio.h"
GPIO_PinState get_key0_val();
GPIO_PinState get_key1_val();
GPIO_PinState get_key2_val();
uint8_t KEY_0(void);
uint8_t KEY_1(void);
uint8_t KEY_2(void);
#endif /* KEY_H_ */
????????key.c內(nèi)容如下:
/*
* key.c
*
* Created on: Sep 29, 2022
* Author: py_hp
*/
#include "key.h"
GPIO_PinState get_key0_val()
{
return HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin);
};
GPIO_PinState get_key1_val()
{
return HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin);
};
GPIO_PinState get_key2_val()
{
return HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
};
uint8_t KEY_0(void)
{
uint8_t a;
a=0;//如果未進(jìn)入按鍵處理,則返回0
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){//讀按鍵接口的電平
HAL_Delay(20);//延時(shí)去抖動(dòng)
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){ //讀按鍵接口的電平
a=1;//進(jìn)入按鍵處理,返回1
}
}
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET); //等待按鍵松開
return a;
}
uint8_t KEY_1(void)
{
uint8_t a;
a=0;//如果未進(jìn)入按鍵處理,則返回0
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){//讀按鍵接口的電平
HAL_Delay(20);//延時(shí)去抖動(dòng)
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET){ //讀按鍵接口的電平
a=1;//進(jìn)入按鍵處理,返回1
}
}
while(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET); //等待按鍵松開
return a;
}
uint8_t KEY_2(void)
{
uint8_t a;
a=0;//如果未進(jìn)入按鍵處理,則返回0
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){//讀按鍵接口的電平
HAL_Delay(20);//延時(shí)去抖動(dòng)
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET){ //讀按鍵接口的電平
a=1;//進(jìn)入按鍵處理,返回1
}
}
while(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET); //等待按鍵松開
return a;
}
????????在main.c中調(diào)用串口驅(qū)動(dòng),其部分代碼如下:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//用戶代碼1
#include "../../ICore/key.h"
#include "../../ICore/led.h"
#include "../../ICore/print.h"
#include "../../ICore/usart.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_LPUART1_UART_Init();
/* USER CODE BEGIN 2 */
//用戶代碼2
ResetPrintInit(&hlpuart1);
HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再開啟接收中斷
HLPUSART_RX_STA = 0;
set_led0_val(0);
set_led1_val(get_key0_val());
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//用戶代碼3
if(KEY_1()) //按鍵KEY1判斷為1時(shí)按鍵按下
{
set_led0_val(1);//LED1燈控制(1點(diǎn)亮,0熄滅)
set_led1_val(0);//LED2燈控制(1點(diǎn)亮,0熄滅)
printf("KEY1\r\n");//向USART1串口發(fā)送字符串
}
if(KEY_2()) //按鍵KEY2判斷為1時(shí)按鍵按下
{
set_led0_val(0);//LED1燈控制(1點(diǎn)亮,0熄滅)
set_led1_val(1);//LED2燈控制(1點(diǎn)亮,0熄滅)
printf("KEY2\r\n");//向USART1串口發(fā)送字符串
}
if(HLPUSART_RX_STA&0xC000){//串口1判斷中斷接收標(biāo)志位
printf("read flag HLPUSART_RX_STA&0XC000\r\n");//向USART1串口發(fā)送字符串
if(HLPUSART_RX_BUF[0]=='1'){
set_led0_val(1);//LED1燈控制(1點(diǎn)亮,0熄滅)
set_led1_val(1);//LED2燈控制(1點(diǎn)亮,0熄滅)
}
if(HLPUSART_RX_BUF[0]=='0'){
set_led0_val(0);//LED1燈控制(1點(diǎn)亮,0熄滅)
set_led1_val(0);//LED2燈控制(1點(diǎn)亮,0熄滅)
}
HLPUSART_RX_STA=0;//串口接收標(biāo)志清0,即開啟下一輪接收
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
四、編譯測(cè)試
??????? 編譯及加載程序到開發(fā)板:
?????????驗(yàn)證數(shù)據(jù)收發(fā),按鍵1和按鍵2按下,順利傳輸數(shù)據(jù),輸入“1”和“0”字段,可下行控制LED燈文章來源:http://www.zghlxwxcb.cn/news/detail-402554.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-402554.html
到了這里,關(guān)于STM32CubeIDE開發(fā)(四), stm32調(diào)試信息串口通信輸出顯示的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!