当前位置: 首页 > article >正文

【串口收发不定长数据】使用中断的方式—以AT32为例

使用中断方式

这种在数据接收不频繁状态下使用,简单易实现。

既然是使用中断,所以自然需要硬件的支持,比如AT32,stm32就可以这么做,关于USART具体的原理、配置及使用详见:【雅特力AT32】串口入门实战:轮询、中断、SWAP(收发管脚交换)功能

关键代码
uint8_t Serial_RxFlag;		// 定义串口接收的标志位变量

char rxdata[20];			// 接收数据缓存区
uint8_t rx_dat;				// 接收字节转运
uint32_t rx_pointer;		// 缓存区指针

/**
  * 函    数:USART收发中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异且与使能函数对应,否则中断函数将不能进入卡死(特别注意接收中断使能后测试)
  * 		  USART_RDBF_FLAG		USART_TDC_FLAG
  */
void USART2_IRQHandler(void)
{
    if(usart_flag_get(MY_USART, USART_RDBF_FLAG) != RESET) 	// 接收数据缓冲区满标志
	{
		Serial_RxFlag = 1;
		
		/* 读取并存放数据寄存器的数据 */
		rx_dat = usart_data_receive(MY_USART);				
		rxdata[rx_pointer++] = rx_dat;						
	}
}

/**
  * 函    数:USART接收不定长数据并进行发送测试
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为USART接收数据的处理函数
  *           可以放在主函数测试,xcom发送任意信息,AT32接收后再转发给xcom
  *           注意测试字符串长度与temp的大小,可自定义更改
  */
void usart_proc(void)
{
	
	if(rx_pointer != 0)
	{	
		uint16_t rx_test = rx_pointer;		
		delay_ms(1);
		/* 确保数据包已传输完毕	*/
		if(rx_pointer == rx_test)		
		{
			/* 打印接收的数据 */
			Serial_SendArray((uint8_t *)rxdata, strlen(rxdata));

			/* 更新缓冲区及指针状态 */
			rx_pointer = 0;
			memset(rxdata,0,20);
		}
	}
}


完整代码

my_usart.c
以AT32为例,包括串口收发配置、中断接收;发送字符(串)、数组、数字的函数封装。

#include "my_usart.h"


uint8_t Serial_RxData;		// 定义串口接收的数据变量
uint8_t Serial_RxFlag;		// 定义串口接收的标志位变量

char rxdata[20];			// 接收数据缓存区
uint8_t rx_dat;				// 接收字节转运
uint32_t rx_pointer;		// 缓存区指针

#define MY_USART USART2

/**
  * @brief  config usart
  * @param  none
  * @retval none
  */
void usart_configuration(void)
{
	
  gpio_init_type gpio_init_struct;

  /* enable the usart2 and gpio clock */
  crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);
  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

  gpio_default_para_init(&gpio_init_struct);

  /* configure the usart2 tx, rx pin */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  gpio_init_struct.gpio_pins = GPIO_PINS_2 | GPIO_PINS_3;
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  gpio_init(GPIOA, &gpio_init_struct);
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_7);	//tx
  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE3, GPIO_MUX_7);	//rx

	/* config usart nvic interrupt */
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  nvic_irq_enable(USART2_IRQn, 0, 0);

  /* configure usart2 param */
  usart_init(MY_USART, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);	

  /* USART2 Send and receive enable */
  usart_transmitter_enable(MY_USART, TRUE);							
  usart_receiver_enable(MY_USART, TRUE);							

  /* enable usart2 and usart3 interrupt */
  usart_interrupt_enable(MY_USART, USART_RDBF_INT, TRUE);					

   usart_enable(MY_USART, TRUE);	

}


/**
  * 函    数:USART2收发中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异且与使能函数对应,否则中断函数将不能进入卡死(特别注意接收中断使能后测试)
  * 		  USART_RDBF_FLAG		USART_TDC_FLAG
  */
void USART2_IRQHandler(void)
{
    if(usart_flag_get(MY_USART, USART_RDBF_FLAG) != RESET) 	// 接收数据缓冲区满标志
	{
		Serial_RxFlag = 1;
		
		/* 读取并存放数据寄存器的数据 */
		rx_dat = usart_data_receive(MY_USART);				
		rxdata[rx_pointer++] = rx_dat;						
	}
}

/**
  * 函    数:USART接收不定长数据并进行发送测试
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为USART接收数据的处理函数
  *           可以放在主函数测试,xcom发送任意信息,AT32接收后再转发给xcom
  *           注意测试字符串长度与temp的大小,可自定义更改
  */
void usart_proc(void)
{
	
	if(rx_pointer != 0)
	{	
		uint16_t rx_test = rx_pointer;		
		delay_ms(1);
		/* 确保数据包已传输完毕	*/
		if(rx_pointer == rx_test)		
		{
			/* 打印接收的数据 */
			Serial_SendArray((uint8_t *)rxdata, strlen(rxdata));

			/* 更新缓冲区及指针状态 */
			rx_pointer = 0;
			memset(rxdata,0,20);
		}
	}
}




/**
  * 函    数:串口发送一个数组
  * 参    数:data 要发送数组的首地址
  * 参    数:size 要发送数组的长度
  * 返 回 值:无
  */
void UART_Write_Blocking(uint8_t* data,uint16_t size)
{
	uint16_t i = 0;
	while(usart_flag_get(MY_USART, USART_TDBE_FLAG) == RESET);		//传输数据缓冲区空标志
	usart_flag_clear(MY_USART, USART_TDBE_FLAG);
	
	for(i=0;i<size;i++)
	{
		usart_data_transmit(MY_USART, (uint16_t)data[i]);
		
		while(usart_flag_get(MY_USART, USART_TDC_FLAG) == RESET);
		usart_flag_clear(MY_USART,USART_TDC_FLAG);
	}
}

/**
  * 函    数:串口发送一个字节
  * 参    数:Byte 要发送的一个字节
  * 返 回 值:无
  */
void Serial_SendByte(uint8_t Byte)
{
	while(usart_flag_get(MY_USART, USART_TDBE_FLAG) == RESET);		//传输数据缓冲区空标志
	usart_flag_clear(MY_USART, USART_TDBE_FLAG);
	
	 usart_data_transmit(MY_USART, Byte);		
	
	while(usart_flag_get(MY_USART, USART_TDC_FLAG) == RESET);	//等待发送完成
	
	/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
	usart_flag_clear(MY_USART,USART_TDC_FLAG);
	
}

/**
  * 函    数:串口发送一个数组
  * 参    数:Array 要发送数组的首地址
  * 参    数:Length 要发送数组的长度
  * 返 回 值:无
  */
void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
	uint16_t i;
	for (i = 0; i < Length; i ++)		
	{
		Serial_SendByte(Array[i]);		
	}
}

/**
  * 函    数:串口发送一个字符串
  * 参    数:String 要发送字符串的首地址
  * 返 回 值:无
  */
void Serial_SendString(char *String)
{
	uint8_t i;
	for (i = 0; String[i] != '\0'; i ++)
	{
		Serial_SendByte(String[i]);		
	}
}


/**
  * 函    数:次方函数(内部使用)
  * 返 回 值:返回值等于X的Y次方
  */
uint32_t Serial_Pow(uint32_t X, uint32_t Y)
{
	uint32_t Result = 1;	
	while (Y --)			
	{
		Result *= X;	
	}
	return Result;
}

/**
  * 函    数:串口发送数字
  * 参    数:Number 要发送的数字,范围:0~4294967295
  * 参    数:Length 要发送数字的长度,范围:0~10
  * 返 回 值:无
  */
void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
	uint8_t i;
	for (i = 0; i < Length; i ++)		
	{
		Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');	
	}
}

测试效果

在这里插入图片描述


http://www.kler.cn/news/323183.html

相关文章:

  • 最近职场中的两点感悟与思考
  • C语言 | Leetcode C语言题解之第433题最小基因变化
  • CentOS 系统中设置宝塔面板开机自启
  • 【习题】应用开发安全
  • OpenCV视频I/O(2)视频采集类VideoCapture之检索视频流的各种属性函数get()的使用
  • WinForm程序嵌入Web网页
  • 【论文解读】ECCV2018细粒度分类:自监督机制NTS-Net模型引领新方向 (附论文地址)
  • 隐蔽通信中KL散度多码字联合与单码字分布
  • Spring Boot打造:小徐影院管理平台
  • SpringCloud Alibaba五大组件之——RocketMQ
  • 【Mysql】Mysql数据库基本操作-------DDL(下)
  • 前端大模型入门:Transformer.js 和 Xenova-引领浏览器端的机器学习变革
  • Kafka与RabbitMQ:深入理解两者之间的区别
  • Rce脚本自动化amp;批量
  • 目标检测系列(三)yolov2的全面讲解
  • ComfyUI 完全入门:基本功能详细介绍(附ComfyUI整合包)
  • 【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)
  • Matlab基础练习
  • 一步步带你Linux内核编译与安装
  • AI编辑器CURSOR_CURSOR安装教程_使用AI进行编码的最佳方式。
  • 论文阅读《Co-clustering for Federated Recommender System》
  • Transformers 引擎,vLLM 引擎,Llama.cpp 引擎,SGLang 引擎,MLX 引擎
  • 每日OJ_牛客_OR59字符串中找出连续最长的数字串_双指针_C++_Java
  • 新茶饮卷出海,本土化成胜败关键
  • 牛肉高脂猫粮,福派斯猫粮新选择?乳鸽猫粮
  • zookeeper 服务搭建(单机)
  • 远程访问软路由
  • [半导体检测-8]:KLA Surfscan 系统设备组成
  • 深度学习----------------------语言模型
  • yolov10安装体验