单片机通讯通用框架--UART

1.驱动层(采用空闲中断接收数据,加上之前写的队列方式进行数据解耦)

创建一个接收结构体

static Queue_UART_Para rx_temp = {0};

extern UART_HandleTypeDef huart1;
extern DMA_HandleTypeDef hdma_usart1_rx;

初始化UART_DMA接收

void Driver_UART_Init_Config(void)
{
	HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *)&rx_temp.Buffer, QueueUARTRxBufMax);
}

在空闲回调函数修改下

Function_Queue_UART_Rx_Push_aData:是将数据压入队列中

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance == USART1)
	{
		rx_temp.Count = QueueUARTRxBufMax - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
		Function_Queue_UART_Rx_Push_aData(rx_temp);
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1, (uint8_t *)&rx_temp.Buffer, QueueUARTRxBufMax);
	}
}

2.任务层(这里借鉴MODBUS的协议进行修改)

HAL_UART_GetState:判断当前的状态,因为要用到rx_temp的数据,所以在发送的时候不能破坏数据

Function_Queue_UART_Rx_Pop_aData:是将数据取出来,我用10ms一次进行轮询

Command_UART_Set_Function:这是进行子命令的函数,下面会解释

void Task_UART(void)
{	
	uint16_t crc16_temp;
	static Queue_UART_Para rx_temp;
	extern UART_HandleTypeDef huart1;

	if(HAL_UART_GetState(&huart1) != HAL_UART_STATE_BUSY_TX)
	{
		if(Function_Queue_UART_Rx_Pop_aData(&rx_temp) == Queue_OK)
		{
			crc16_temp = CRC_16((uint8_t *)&rx_temp.Buffer, rx_temp.Count - 2);
			
			if(crc16_temp == ((rx_temp.Buffer[rx_temp.Count - 1] << 8) | rx_temp.Buffer[rx_temp.Count - 2]))
			{
				if(rx_temp.Buffer[UART_Address] == 0xFF || rx_temp.Buffer[UART_Address] == Driver_Read_Flash(UART1_Address))
				{
					if(Command_UART_Set_Function(rx_temp.Buffer[UART_ID], (void *)&rx_temp.Buffer) == Command_ERROR)
					{
						Debug("It is not this command!\r\n");
					}
				}
			}
			else
			{
				if(Driver_Read_Flash(UART_CDC_USB_TT_Mode) == USB_CDC_Normal)
				{
					Debug("Modebus CRC16 Cheak is Error!\r\n");
				}
				else
				{
					CDC_Transmit_HS((uint8_t *)&rx_temp.Buffer, rx_temp.Count);
				}
			}
		}
	}
}

3.命令层

命令层.h文件

/**
 *  @brief UART数据帧结构定义
 */
typedef enum
{
	UART_Address = 0,							/*!< UART接收数据帧起始地址 */
	UART_Function,								/*!< UART接收数据帧功能地址 */
	UART_ID,									/*!< UART接收数据帧ID地址 */
	UART_DataNum,								/*!< UART接收数据帧数据个数 */
	UART_DataStart								/*!< UART接收数据帧数据起始位 */
} UART_Type;


#define Command_UART_Read_ID		0x03		/*!< UART接收帧读功能 */
#define Command_UART_Write_ID		0x10		/*!< UART接收帧写功能 */
typedef void (*Command_UART)(void *Buf);		/*!< UART任务命令重定义 */


Command_StatusTypeDef Command_UART_Set_Function(uint8_t ID, void *Buf);

命令层解析.h文件

命令解析需要主要字节对齐,这里在队列的数据中已经做了处理

#include "stdint.h"
#include "stddef.h"


#define Command_UART_DBC_Max_Buf			16
#define Command_UART_DBC_Head_Frame_Buf		4
#define Command_UART_DBC_CRC16				2
#define Command_UART_DBC_Buf				Command_UART_DBC_Max_Buf - Command_UART_DBC_Head_Frame_Buf

/**
 *  @brief 串口DBC帧头数据
 */
typedef struct __Command_UART_DBC_Head_Frame
{
	uint8_t Address;
	uint8_t Function;
	uint8_t ID;
	uint8_t DataNum;
} Command_UART_DBC_Head_Frame;



/**
 *  @brief 设置地址
 */
typedef union
{
	uint8_t Buf[Command_UART_DBC_Max_Buf];
	struct
	{
		Command_UART_DBC_Head_Frame Head_Frame;
		
		struct __Data_0
		{
			uint16_t SetAddr;
		} Data;
		
		uint8_t Reserve[Command_UART_DBC_Buf - sizeof(struct __Data_0)];
	} bit;
} Command_UART_DBC_Set_OwnAddress;

命令层.c文件

这里需要保证每个数据帧的ID和命令的ID一样

#include "Command_UART.h"
#include "Command_UART_DBC.h"


/*!< UART功能命令函数 */
static void Command_UART_Set_OwnAddress(void *Buf);
static void Command_UART_Read_FreeRTOS_WaterMark(void *Buf);
static void Command_UART_W25Qxx_Test(void *Buf);
static void Command_UART_ST7735_Test(void *Buf);


/*!< UART功能命令列表 */
static const Command_UART  	CMD_UART[] = 
{
	Command_UART_Set_OwnAddress,
	Command_UART_Read_FreeRTOS_WaterMark,
	Command_UART_W25Qxx_Test,
	Command_UART_ST7735_Test,
};


/*********************************************************************
 * @fn      Command_UART_Set_Function
 *
 * @brief   UART功能命令设置函数.
 *
 * @param	ID:功能ID号.
 *
 * @param   Buf:接收数据帧.
 *
 * @return  Command_StatusTypeDef:状态标志位
 */
Command_StatusTypeDef Command_UART_Set_Function(uint8_t ID, void *Buf)
{
	if(ID < (sizeof(CMD_UART)/sizeof(CMD_UART[0])))
	{
		CMD_UART[ID]((void *)Buf);
		return Command_OK;
	}
	return Command_ERROR;
}


/*********************************************************************
 * @fn      Command_UART_Set_OwnAddress
 *
 * @brief   UART读取设置自身地址.
 *
 * @param   Buf:接收数据帧
 *
 * @return  none
 */
static void Command_UART_Set_OwnAddress(void *Buf)
{
	Command_UART_DBC_Set_OwnAddress *temp = (Command_UART_DBC_Set_OwnAddress *)Buf;
	
	if(temp->bit.Head_Frame.Function == Command_UART_Read_ID)
	{
		Debug("UART Address is %d", Driver_Read_Flash(UART1_Address));
	}
	else if(temp->bit.Head_Frame.Function == Command_UART_Write_ID)
	{
		//Driver_Write_Flash(UART1_Address, temp->bit.Data.SetAddr, ENABLE);
		if(temp->bit.Data.SetAddr)
		{
			Debug("UART Set Address is %d succ", temp->bit.Data.SetAddr);
		}
		
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值