stm32的工程可以直接使用C标准库函数,其中printf函数没有完全实现,预留了一个后门fputc函数,可以通过实现fputc往串口打印从而实现printf的功能。
1.fputc格式:
int fputc(int ch,FILE *F) { //...... }
//stm32开发板上运行程序,如果主机运行了调试器,程序就会使用主机的输入输出设备
//这是方式叫半主机模式,printf如果要通过串口打印,必须关闭半主机模式 #pragma import(__use_no_semihosting)
struct __FILE{ int handle; };
FILE __stdout;
//定义_sys_exit函数避免使用半主机模式
void _sys_exit(int x) { x = x; } //重定义fputc
int fputc(int ch,FILE *F) { //发送 USART_SendData(USART1,ch);
//等待上一个数据发送完成
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); return ch; }
———————————————————————————————————————————
2.使用中断实现串口的接收
由于串口何时发送数据由CPU决定,不存在无效等待的问题,可以不使用中断,但是串口的接收不由CPU决定何时接收,如果还使用轮询就会存在大量无效等待,此时要使用中断提供效率。
串口中断和定时器中断类似,需要配置中断开关和NVIC。
NVIC_Init(...);//初始化函数
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断
在串口中断处理函数中完成数据的接收
void USART1_IRQHandler(void) {
//判断是否为接收中断 ---------- USART_GetITStatus(USART1, USART_IT_RXNE);
//接收数据 ------------------- data = USART_ReceiveData(USART1);
//清除中断标志 --------------- USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
练习:
为串口中断实现数据接收和控制命令控制蜂鸣器主要功能函数
- #include <stm32f4xx.h>
- #include <usart.h>
- #include <stdio.h>
- #include <string.h>
- #include <includes.h>
-
- //stm32开发板上运行程序,如果主机运行了调试器,程序就会使用主机的输入输出设备
- //这是方式叫半主机模式,printf如果要通过串口打印,必须关闭半主机模式
- #pragma import(__use_no_semihosting)
-
- struct __FILE{
- int handle;
- };
-
- FILE __stdout;
-
- //定义_sys_exit函数避免使用半主机模式
- void _sys_exit(int x)
- {
- x = x;//这里的赋值没有实际意义,避免空函数
- }
-
- //重定义fputc
- int fputc(int ch,FILE *F)
- {
- //等待上一个数据发送完成
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
- //发送
- USART_SendData(USART1,ch);
-
- return ch;
- }
-
- void usart1_init(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct;
- USART_InitTypeDef USART_InitStruct;
- NVIC_InitTypeDef NVIC_InitStruct;
-
- //1.开启GPIOA和USART1时钟
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
-
- //2.配置PA9 PA10为串口功能
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
- GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//高速
- GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
- GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
- GPIO_Init(GPIOA,&GPIO_InitStruct);
-
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
- GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
-
- //3.初始化串口 8N1
- USART_InitStruct.USART_BaudRate = 115200;//波特率
- USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位数据位
- USART_InitStruct.USART_StopBits = USART_StopBits_1;//1位停止位
- USART_InitStruct.USART_Parity = USART_Parity_No;//无校验
- USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//发送接收模式
- USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件流控制
- USART_Init(USART1,&USART_InitStruct);
-
- //4.开启串口接收中断(清除中断标志)
- USART_ClearITPendingBit(USART1, USART_IT_RXNE);
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
-
- //5.初始化NVIC
- NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
- NVIC_Init(&NVIC_InitStruct);
-
- //.使能串口
- USART_Cmd(USART1,ENABLE);
- }
-
- //发送一个字符(轮询)
- void uart1_putc(char ch)
- {
- //等待上一个数据发送完成
- while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
-
- USART_SendData(USART1,ch);
- }
-
- //发送字符串
- void uart1_puts(const char *s)
- {
- while(*s){
- uart1_putc(*s++);
- }
- }
-
- volatile u32 uart_flag = 0;//记录串口是否收到了一个完整的数据 1---完整
- volatile u8 uart_buf[64] = {0};//记录串口收到的数据
- volatile u32 uart_cnt = 0;//记录串口收到的数据长度
-
- //处理串口命令函数
- void parse_cmd(void)
- {
- while(1){
- if(uart_flag){
- //BEEP命令
- if(strstr((char *)uart_buf,"beep")){
- if(strstr((char *)uart_buf,"on")){
- BEEP = 1;
- printf("beep on!\r\n");
- }
-
- if(strstr((char *)uart_buf,"off")){
- BEEP = 0;
- printf("beep off!\r\n");
- }
- }
- else{//非法命令
- printf("unknow command = %s\r\n",(char *)uart_buf);
- }
-
- //处理完成标志清0,缓冲区清空,个数清0
- uart_flag = 0;
- memset((char *)uart_buf,0,sizeof(uart_buf));
- uart_cnt = 0;
- }
- }
- }
-
- //串口1中断处理函数
- void USART1_IRQHandler(void)
- {
- //u8 data;
-
- if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET){
- //接收串口数据
- uart_buf[uart_cnt++] = USART_ReceiveData(USART1);
-
- //判断数据是否接收完成 ------ 以*结束
- if(uart_buf[uart_cnt-1]=='*'||uart_cnt>=sizeof(uart_buf)){
- uart_flag = 1;
- }
-
- //原路发回
- //uart1_putc(data);
-
-
- USART_ClearITPendingBit(USART1, USART_IT_RXNE);
- }
- }