USART电路说明
首先了解编译调试硬件连接,查看原理图
STM32F103RCT6开发板用Jlink供电,USB转串口板电脑USB供电,那么连接只需3线
* TXD(PB9) -> USB转串口板RXD
* RXD(PB10) -> USB转串口T板XD
* GND -> USB转串口板GND
编写代码
- 复制上节工程文件夹打开(这个方法比较方便)
- 新建源文件usart.c,添加usart.c到BSP(Grounp),并编辑
/********************************************************************************** * 文件名 :usart.c * 描述 :usart1 应用函数库 * 实验平台:SUN_STM32F1板 * 硬件连接:TXD(PB9) -> USB转串口板RXD * RXD(PB10) -> USB转串口T板XD * GND -> USB转串口板GND * 库版本 :ST_v3.5 * Version Date Auther Reversed History ---------------------------------------------------------------------------- V1.0.0 2021-11-07 Lojam Fan Fisrt Created * (C) Sunshine Silicon Corporation * Website: http://www.sunsili.com http://sunsili.taobao.com http://bbs.sunsili.com * E-Mail : fan@sunsili.com **********************************************************************************/ #include "usart.h" vu8 Usart1_R_Buff[USART1_REC_MAXLEN]; //串口1数据接收缓冲区 vu8 Usart1_R_State=0; //串口1接收状态 vu16 Usart1_R_Count=0; //当前接收数据的字节数 /******************************************************************************* * 函数名 : USART1_Init_Config * 描述 : USART1初始化配置 * 输入 : bound:波特率(常用:2400、4800、9600、19200、38400、115200等) * 输出 : 无 * 返回 : 无 * 说明 : 无 *******************************************************************************/ void USART1_Init_Config(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; /*使能USART1和GPIOA外设时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); /*复位串口1*/ USART_DeInit(USART1); /*USART1_GPIO初始化设置*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //USART1_TXD(PA.9) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚输出最大速率为50MHz GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数中的GPIO初始化函数,初始化USART1_TXD(PA.9) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //USART1_RXD(PA.10) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //调用库函数中的GPIO初始化函数,初始化USART1_RXD(PA.10) /*USART1 初始化设置*/ USART_InitStructure.USART_BaudRate = bound; //设置波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1个停止位 USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //工作模式设置为收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 /*Usart1 NVIC配置*/ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能串口1接收中断 USART_Cmd(USART1, ENABLE); //使能串口 USART_ClearFlag(USART1, USART_FLAG_TC); //清除发送完成标志 } /******************************************************************************* * 函数名 : USART_SendData * 描述 : USART1发送数据缓冲区数据 * 输入 : *buff:数据缓冲区指针,len:发送数据长度 * 输出 : 无 * 返回 : 无 * 说明 : 无 *******************************************************************************/ void USART1_SendData(u8* buff, u16 len) { u16 i; for(i=0; i<len; i++) { while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); USART_SendData(USART1 ,buff[i]); } } /******************************************************************************* * 函数名 : USART1_IRQHandler * 描述 : 串口1中断服务程序 * 输入 : 无 * 返回 : 无 * 说明 : 1)、只启动了USART1中断接收,未启动USART1中断发送。 * 2)、接收到0x0d 0x0a(回车、"\r\n")代表帧数据接收完成 *******************************************************************************/ void USART1_IRQHandler(void) { u8 Res=0; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { Res =USART_ReceiveData(USART1); //读取接收到的数据(USART1->DR) Usart1_R_Buff[Usart1_R_Count++] = Res; if(Usart1_R_State == 0)//数据接收未完成 { if(Res == 0x0d)//接收到0x0d,下一个字节接收到0x0a则接收完成 { Usart1_R_State =2; } } else if(Usart1_R_State == 2) { if(Res == 0x0a)//上一个字节接收到0x0d,这个字节接收到oxoa则接收完成 { Usart1_R_State =1;//数据接收完成 } else//接收错误 { Usart1_R_State =0; Usart1_R_Count =0; } } if(Usart1_R_Count >= USART1_REC_MAXLEN)//接收数据长度走出接收数据缓冲区 { if((Usart1_R_Buff[USART1_REC_MAXLEN-2] != 0x0d) || (Usart1_R_Buff[USART1_REC_MAXLEN-1] != 0x0a)) { Usart1_R_Count =0; Usart1_R_State =0; } } } } /******************* (C) COPYRIGHT SUNSHINE SILICON ************************** ******************** END OF FILE usart.c *******************/
- 新建源文件usart.h,并编辑
#ifndef __USART_H #define __USART_H #include "stm32f10x.h" #include <stdio.h> #define USART1_REC_MAXLEN 200 //最大接收数据长度 void USART1_Init_Config(u32 bound); void USART1_SendData(u8* buff, u16 len); //int fputc(int ch, FILE *f); //void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...); #endif /******************* (C) COPYRIGHT SUNSHINE SILICON ************************** ******************** END OF FILE usart.h *******************/
- 编辑main.c
/********************************************************************************** * Sun STM32 mini Demo * Description Uart Demo * Version Date Auther Reversed History ---------------------------------------------------------------------------- V1.0.0 2021-11-07 Lojam Fan Fisrt Created * (C) Sunshine Silicon Corporation * Website: http://www.sunsili.com http://sunsili.taobao.com http://bbs.sunsili.com * E-Mail : fan@sunsili.com **********************************************************************************/ #include "stm32f10x.h" #include "usart.h" #include "SysTick.h" #include "led.h" #include <stdio.h> extern vu8 Usart1_R_Buff[USART1_REC_MAXLEN]; //串口1数据接收缓冲区 extern vu8 Usart1_R_State; //串口1接收状态 extern vu16 Usart1_R_Count; //当前接收数据的字节数 /******************************************************************************* * 函数名 : main * 描述 : 主函数,用户程序从main函数开始运行 * 输入 : 无 * 输出 : 无 * 返回值 : int:返回值为一个16位整形数 * 说明 : 无 *******************************************************************************/ int main(void) { SysTick_Init_Config(); USART1_Init_Config(115200);//USART1初始化配置 LED_GPIO_Config(); printf ("*===================================================*\n"); printf ("* * Name: Sun STM32 mini Demo Code. *************\n"); printf ("* * (C) Sunshine Silicon Corporation *************\n"); printf ("* * Website: http://www.sunsili.com *************\n"); printf ("* * E-Mail : fan@sunsili.com *************\n"); printf ("*===================================================*\n"); printf ("* Sun STM32 mini uart transmit the same data to PC .*\n"); while (1) { if(Usart1_R_State == 1)//一帧数据接收完成 { USART1_SendData((u8 *)Usart1_R_Buff, Usart1_R_Count); //USART1发送数据缓冲区数据(发送刚接收完成的一帧数据) Usart1_R_State =0; Usart1_R_Count =0; } printf("Hello Sunshine Silicon!\r"); LED4_ON(); Delay_nMs(500); LED4_OFF(); Delay_nMs(500); } } /******************* (C) COPYRIGHT SUNSHINE SILICON ************************** ******************** END OF FILE main.c *******************/
编译调试
方法不再重复,经过前两节练习,大家应该是会了.
但发现程序不跑了,单调试发现程序卡在printf不动了。为什么呢?因为MCU不像电脑只要添加stdio.h, 就能用printf。MCU要重定向c库函数printf到USART1(不一定USART1,实际用哪个定义到哪个),标准库代码内容还会被优化掉,编译时不输出。如何让它跑起来了呢。
在usart.c中添加函数
///重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return (ch);
}
///重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
设置编译时,加入MCU适用标准库函数
再次编译调试一切如愿。符合我们当初的设计。
工程下载
查看原文,可下载工程源码