通过串口实现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函数,中断实现串口数据接收 的相关文章

  • printf 忽略单个反斜杠 '\'

    我有这个代码 int main int argc char argv int i printf d s argc argv 1 return 0 如果我运行这段代码a out a b 我在用C shell 其输出为 a b 有什么方法可以将
  • 使用 system.out.printf 格式化 java 字符串

    我一直在寻找很多关于 java 中的 System out printf 格式化字符串输出的问题 但我似乎不明白如何使用它 我正在尝试打印看起来像这样的漂亮专栏 601 GoPro Hero5 Black 276 95 602 GoPro
  • 为什么在使用 wprintf 时将 ©(版权符号)替换为 (C)?

    当我尝试打印版权符号时 with printf or write 它工作得很好 include
  • 关于 printf 语句的混淆

    所以我正在运行这段代码 include
  • 在 Perl 中我应该使用什么来代替 printf ?

    我需要在 Perl 中使用一些字符串替换来简化翻译 即替换许多 print Outputting n numbers 通过类似的东西 printf Outputting d numbers n 但是 我想用更易于人类解析的内容替换 prin
  • 打印 C 字符串(UTF-8)时的 NSLog() 与 printf()

    我注意到 如果我尝试使用格式说明符 s 打印包含 UTF 8 字符串表示形式的字节数组 printf 说得对 但是NSLog 得到它乱码 即 每个字节按原样打印 因此例如 被打印为2个字符 这很奇怪 因为我一直认为NSLog 只是print
  • 混淆 .fmt 行为与嵌套列表

    The docs https docs raku org routine fmt比如说fmt 返回一个字符串 其中列表中的每个元素都已根据以下格式进行格式化 format 第一个参数 并且每个元素由 separator 第二个论点 根据该描
  • php sprintf() 包含外来字符?

    接缝就像 sprintf 有外来字符的问题 还是我做错了什么 看起来它在从字符串中删除像 这样的字符时有效 有必要吗 我希望以下几行能够正确对齐以生成报告 2011 11 27 A1823 Ref Leif 12 873 00 18 98
  • 如何使用“%f”将双精度值填充到具有正确精度的字符串中

    我正在尝试使用 a 来填充带有双精度值的字符串sprintf像这样 sprintf S f val 但精度被截断至小数点后六位 我需要大约 10 位小数来保证精度 如何才能做到这一点 宽度 精度 宽度应包括小数点 8 2表示8个字符宽 点前
  • printf 类型提升和符号扩展

    我对 printf 和一般情况下类型提升如何发生感到困惑 我尝试了以下代码 unsigned char uc 255 signed char sc 128 printf unsigned char value d n uc printf s
  • 在 MATLAB 中使用 sprintf 显示变量的小数

    我不明白接下来会发生什么sprintf http www mathworks se help techdoc ref sprintf html命令 gt gt vpa exp 1 53 ans 2 718281828459045534884
  • 如何使用 sprintf 附加字符串?

    我面临着一个严重的问题sprintf 假设我的代码片段是 sprintf Buffer Hello World sprintf Buffer Good Morning sprintf Buffer Good Afternoon 几百次冲刺
  • 向 printf 传递太多参数

    任何已经工作了一周以上的 C 程序员都遇到过因调用而导致的崩溃printf格式说明符多于实际参数 例如 printf Gonna s and s s crash burn 然而 当你通过时 是否会发生类似的糟糕事情 too manyprin
  • 如何在 C++ 中的特定坐标处将字符串打印到控制台?

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

    所以 我有点难受 根据man 3 printf在我的系统上 字符串格式 5s 应使用指定的精度来限制从给定字符串参数打印的字符数 man 3 printf PRINTF 3 BSD Library Functions Manual PRIN
  • C 编程:正向变量参数列表

    我正在尝试编写一个函数 它接受可变数量的参数 如 printf 执行一些操作 然后将变量列表传递给 printf 我不知道如何做到这一点 因为它似乎必须将它们推入堆栈 大约是这样的 http pastie org 694844 http p
  • awk 的 printf 插入多个变量的正确语法是什么?

    我复制了一些使用 printf 输出字符串在文件中出现的频率的代码 awk BEGIN print The number of times a appears in the file a a counter 1 END printf s n
  • C++,关于 fprintf 和 ofstream

    我一直在使用fprintf有一段时间了 我想问一个问题 这个相当于什么fprintf line fprintf OutputFile s SomeStringValue using ofstream 如何在中使用 s ofstream这是我
  • awk 每个文件后换行

    使用此脚本 每个字段都会根据当前文件的最长单词打印出来 但需要每个文件都有一个换行符 如何才能实现这一目标 awk BEGIN ORS n FNR NR a i 0 if length 0 gt length max max 0 l len
  • en_CA 语言环境中 sprintf 中的逗号作为小数分隔符

    是否可以在 en CA 语言环境中的 sprintf 中使用逗号作为小数点分隔符 sprintf 能够识别区域设置 并且将始终使用当前的区域设置 但您可以使用数字格式 http php net manual en function numb

随机推荐