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);
}
}