通过串口实现printf函数,中断实现串口数据接收

2023-05-16

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过串口实现printf函数,中断实现串口数据接收 的相关文章

  • MinGW 的 msvcrt 替代品? (例如,获得符合要求的 snprintf)

    所以这是一个有趣的 我们有一些 C 库should与平台无关 即使它们是在 Linux 上开发的 因为它们仅依赖于 ISO IEC 9899 1999 中定义的 C 标准库 当我们用 MinGW 编译这些库时 一开始一切似乎都工作正常 但今
  • 正则表达式精确单词匹配

    我需要匹配行中的单词 例如 The blue bird is dancing Yellow card is drawn The day is perfect rainy blue bird is eating 这四行位于文本文件中l2 我想
  • 如何使用 printf 打印字符串而不打印尾随换行符

    I m trying to print some strings using printf but they are null terminated having trailing newline and that messes with
  • 针对 arm64 和 32 位架构进行编译时的基础类型

    在为 arm64 编译 iOS 应用程序的代码时 我遇到了一个有趣的问题 该问题与自定义 Foundation 类型的不同基本类型有关 假设我想 printf 或 stringWithFormat 声明为的数字NSU整数 NSString
  • printf 命令导致段错误? [复制]

    这个问题在这里已经有答案了 当我尝试初始化一个大型的二维字符数组时 它工作得很好 但是当我添加一个简单的打印命令时 它给了我一个分段错误 关于为什么会发生这种情况有什么想法吗 include
  • 向 printf 传递太多参数

    任何已经工作了一周以上的 C 程序员都遇到过因调用而导致的崩溃printf格式说明符多于实际参数 例如 printf Gonna s and s s crash burn 然而 当你通过时 是否会发生类似的糟糕事情 too manyprin
  • 使用 OpenMP 时无用的 printf 没有加速

    我刚刚编写了第一个 OpenMP 程序 它并行化了一个简单的 for 循环 我在双核机器上运行代码 发现从 1 个线程变为 2 个线程时速度有所提高 然而 我在学校 Linux 服务器上运行相同的代码并没有看到加速 在尝试了不同的事情之后
  • 如何在 C++ 中的特定坐标处将字符串打印到控制台?

    我正在尝试在控制台中的指定坐标处打印字符 到目前为止我一直在使用非常丑陋的printf 033 d dH s n 2 2 str 但我只想问 C 是否有其他方法可以做到这一点 问题甚至不在于它丑陋 当我试图让自己成为一个更漂亮的函数时 问题
  • printf 字符串,可变长度项

    define SIZE 9 int number 5 char letters SIZE this wont be null terminated char fmt string 20 sprintf fmt string d ds SIZ
  • 左填充 printf 带空格

    使用 printf 时如何在字符串左侧填充空格 例如 我想打印 Hello 前面有 40 个空格 另外 我要打印的字符串由多行组成 我需要单独打印每一行吗 编辑 为了明确起见 我希望在每行之前打印 40 个空格 如果您希望在 40 个字符宽
  • scanf %u 负数?

    我努力了scanf u number 我输入了负数 问题是当我printf d number 我得到负数 我认为这会阻止我读取负数 是scanf d number and scanf u number 真的是同一件事吗 或者只是为了可读性
  • 可以使用多个 _Generic 创建字符串文字吗?

    有没有办法使用 Generic在同一表达式中多次使用关键字来创建单个字符串文字 我正在寻找的是一种方法 例如生成要传递给的单个格式字符串printf 所有转换说明符都适应正确的类型 写作时this https stackoverflow c
  • 格式说明符%02x

    我有一个简单的程序 include
  • “%d”需要“int”类型的参数,但参数 2 的类型为“long unsigned int”[-Wformat=] [重复]

    这个问题在这里已经有答案了 我不断收到编译警告 但我不知道如何解决它 d expects argument of type int but argument 2 has type long unsigned int 程序运行良好 但我仍然收
  • awk 每个文件后换行

    使用此脚本 每个字段都会根据当前文件的最长单词打印出来 但需要每个文件都有一个换行符 如何才能实现这一目标 awk BEGIN ORS n FNR NR a i 0 if length 0 gt length max max 0 l len
  • Arduino sprintf float 未格式化

    我有这个arduino草图 char temperature 10 float temp 10 55 sprintf temperature f F temp Serial println temperature 温度打印为 F 关于如何格
  • 在C语言中如何对齐这样的数字?

    我需要将 C 中的一系列数字与printf 就像这个例子 1 5 50 100 1000 当然 所有这些之间都有数字 但这与当前的问题无关 哦 将破折号视为空格 我使用破折号 这样更容易理解我想要的内容 我只能这样做 1 5 50 100
  • Clang 5.0 上的 vsprintf 和 vsnprintf [-Wformat-nonliteral] 警告

    我有这段代码 static void err doit int errnoflag int level const char fmt va list ap int errno save unsigned long n char buf MA
  • 了解如何 printf("%d\n", ( { int n; scanf("%d", &n); n*n; } ));在 C 语言中工作

    我通过一个途径发现了这个程序 include
  • printf() 使用字符串表“解码器环”调试库

    我写这封信是想看看你们中是否有人见过或听说过我即将描述的想法的实现 我有兴趣为嵌入式目标开发 printf 风格的调试库 目标非常遥远 并且我和目标之间的通信带宽预算非常紧张 因此我希望能够以非常有效的格式获取调试消息 通常 调试语句如下所

随机推荐