单片机 串口发送和接收

usart.h

#ifndef UART_H
#define UART_H
#include "at32f403a_407_clock.h"

#define	 	USART_QUEUE_SIZE 					10
#define	 	USART_BUF_SIZE 					  1024

// 队列结构体
typedef struct {
    uint8_t buffer[USART_QUEUE_SIZE][USART_BUF_SIZE]; // 存储队列数据的缓冲区
	  uint16_t len[USART_QUEUE_SIZE]; // 存储队列数据的缓冲区
    uint16_t front;                      // 队头
    uint16_t rear;                       // 队尾
} Usart_Queue;

extern Usart_Queue usart1_queue;

void usart1_init(void);
void usart2_init(void);
void usart_send_byte( usart_type * pUSARTx, uint8_t ch);
void usart_send_string( usart_type * pUSARTx, char *str);
void usart_send_bytes( usart_type * pUSARTx, uint8_t* ch,int len);

void usart_queue_init(Usart_Queue* q);
int usart_queue_enqueue(Usart_Queue* q, uint8_t* data,uint16_t len);
int usart_queue_dequeue(Usart_Queue* q, uint8_t* data);
#endif

usart.c

#include "usart.h"
#include <string.h>


#define	 	USART_HEADER 					  	0X15
#define	 	USART_TAIL 					  		0X16

uint8_t  	usart1_receive_data[USART_BUF_SIZE]; 
uint16_t 	usart1_receive_index=0;
uint8_t   usart1_is_receive_header=0;

Usart_Queue usart1_queue;


//串口1初始化
void usart1_init()
{
	gpio_init_type gpio_init_struct;
	
	usart_queue_init(&usart1_queue);
	
	/* 使能对应端口的时钟 */
  crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
	/* 默认填充配置 */
  gpio_default_para_init(&gpio_init_struct);
	
	/* 设置 GPIO 驱动能力较大电流推动/吸入能力 */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	/* 设置 GPIO 输出类型为推挽输出模式 */
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	/* 设置 GPIO 模式为复用模式 */
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	/* 配置 GPIO 引脚 */
  gpio_init_struct.gpio_pins = GPIO_PINS_9|GPIO_PINS_10;
	/* 设置 GPIO 无上下拉模式 */
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	/* 初始化 GPIO 外设 */
  gpio_init(GPIOA, &gpio_init_struct);


	/* 波特率 数据位 停止位配置 */
  usart_init(USART1, 9600, USART_DATA_8BITS, USART_STOP_1_BIT);
	
	/* 中断优先级分组配置 */
	nvic_priority_group_config(NVIC_PRIORITY_GROUP_1);
	/* 中断使能及优先级配置 */
  nvic_irq_enable(USART1_IRQn, 0,1);

  /* 发送使能 */
  usart_transmitter_enable(USART1, TRUE);
	/* 接收使能 */
  usart_receiver_enable(USART1, TRUE);
  /* 中断使能 */	
	usart_interrupt_enable(USART1,USART_RDBF_INT, TRUE);
  /* 串口使能 */
  usart_enable(USART1, TRUE);
}

//串口2初始化
void usart2_init()
{
	gpio_init_type gpio_init_struct;
	
	/* 使能对应端口的时钟 */
  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);
	
	/* 设置 GPIO 驱动能力较大电流推动/吸入能力 */
  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	/* 设置 GPIO 输出类型为推挽输出模式 */
  gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;
	/* 设置 GPIO 模式为复用模式 */
  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	/* 配置 GPIO 引脚 */
  gpio_init_struct.gpio_pins = GPIO_PINS_2;
	/* 设置 GPIO 无上下拉模式 */
  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	/* 初始化 GPIO 外设 */
  gpio_init(GPIOA, &gpio_init_struct);

  gpio_init_struct.gpio_pins = GPIO_PINS_3;
  gpio_init(GPIOA, &gpio_init_struct);


	/* 波特率 数据位 停止位配置 */
  usart_init(USART2, 9600, USART_DATA_8BITS, USART_STOP_1_BIT);
	
	/* 中断优先级分组配置 */
	nvic_priority_group_config(NVIC_PRIORITY_GROUP_1);
	/* 中断使能及优先级配置 */
  nvic_irq_enable(USART2_IRQn, 0,1);

  /* 发送使能 */
  usart_transmitter_enable(USART2, TRUE);
	/* 接收使能 */
  usart_receiver_enable(USART2, TRUE);
  /* 中断使能 */	
	usart_interrupt_enable(USART2,USART_RDBF_INT, TRUE);
  /* 串口使能 */
  usart_enable(USART2, TRUE);
}


/*****************  发送一个字符 **********************/
void usart_send_byte( usart_type * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	usart_data_transmit(pUSARTx,ch);
		
	/* 等待发送数据寄存器为空 */
	while (usart_flag_get(pUSARTx, USART_TDBE_FLAG) == RESET);	
}

/*****************  发送多个字符 **********************/
void usart_send_bytes( usart_type * pUSARTx, uint8_t* ch,int len)
{
	int i;
	for(i=0;i<len;i++)
	{
		usart_send_byte( pUSARTx, *(ch + i) );
	}
}

/*****************  发送字符串 **********************/
void usart_send_string( usart_type * pUSARTx, char *str)
{
	unsigned int k=0;
  do 
  {
      usart_send_byte( pUSARTx, *(str + k) );
      k++;
  } while(*(str + k)!='\0');
  
  /* 等待发送完成 */
  while(usart_flag_get(pUSARTx,USART_TDC_FLAG)==RESET)
  {}
}

//串口1中断 接收
void USART1_IRQHandler(void)
{
	uint8_t uc;

  if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET)
  {
		uc = usart_data_receive(USART1);
		usart1_receive_data[usart1_receive_index]=uc;
		usart1_receive_index++;
		if(uc==USART_HEADER)usart1_is_receive_header=1;
		if((uc==USART_TAIL&&usart1_receive_index>=6&&usart1_is_receive_header)||usart1_receive_index>=USART_BUF_SIZE)
		{
			usart_queue_enqueue(&usart1_queue,usart1_receive_data,usart1_receive_index);
			//usart_send_bytes(USART1,usart1_receive_data,usart1_receive_index);
			usart1_receive_index=0;
			usart1_is_receive_header=0;
			
		}
  }
}

//串口2中断 接收
void USART2_IRQHandler(void)
{
	uint8_t uc;

  if(usart_flag_get(USART2, USART_RDBF_FLAG) != RESET)
  {
		uc = usart_data_receive(USART2);
		usart_data_transmit(USART2, uc);
  }
}

// 初始化队列
void usart_queue_init(Usart_Queue* q) {
    q->front = 0;
    q->rear = 0;
}

// 判断队列是否为空
int usart_queue_is_empty(Usart_Queue* q) {
    return q->front == q->rear;
}

// 判断队列是否为满
int usart_queue_is_full(Usart_Queue* q) {
    return ((q->rear + 1) % USART_QUEUE_SIZE) == q->front;
}


// 入队操作
int usart_queue_enqueue(Usart_Queue* q, uint8_t* data,uint16_t len) {
    if (usart_queue_is_full(q)) {
        return -1;  // 队列已满,无法入队
    }
		q->len[q->rear]=len;
    memcpy(q->buffer[q->rear], data, USART_BUF_SIZE);  // 复制数据到队列
    q->rear = (q->rear + 1) % USART_QUEUE_SIZE;           // 更新队尾索引
    return 0;
}

// 出队操作
int usart_queue_dequeue(Usart_Queue* q, uint8_t* data) {
		int len=0;
    if (usart_queue_is_empty(q)) {
        return 0;  // 队列为空,无法出队
    }
		len=q->len[q->front];
    memcpy(data, q->buffer[q->front], USART_BUF_SIZE);  // 复制队头数据
    q->front = (q->front + 1) % USART_QUEUE_SIZE;          // 更新队头索引
    return len;
}







main.c

	while(1)
	{
		data_len = usart_queue_dequeue(&usart1_queue, item);
    	// 从队列中出队一个项
    	if (data_len != 0)
		{
			usart_send_bytes(USART1,item,data_len);
    	}
    	delay_ms(10);
	}
		
协议说明: CCU向各个终端所发的数据格式有3种:查询,令牌,广播 查询:CCU向各个终端一对一发送一串数据,CCU在发送完后,终端在一定时间内拥有发言权。 令牌:CCU发出令牌命令后,各个终端收到自己的令牌帧后,拥有总线的发言权, 必须在一定时间内发出帧头,否则,CCU取消该终端的发言权。发言完或者没有发言, 把令牌在规定的时间内传给下一个终端 广播:CCU发出广播帧后,各个终端必须按照广播帧工作,不要回复CCU,也没有总线发言权 格式: 查询:7E, 命令,目标网络,地址,数据长度,数据,校验,7E 令牌:7E,命令,当前虚拟地址,令牌,校验,7E 广播; 7E, FF, FF, FF,数据长度,数据,校验,7E 数据格式说明: 1,7E为帧头,帧尾标志。如果在数据里面遇到有7E,将数据7E拆分为7F,80,如 果数据里面有7F,将7F拆分为7F,81.在接收时,将上面数据合成相应的数。 2,目标网络:为各个终端所在的网络。T/R0 为00,T/R 为01,T/R2 为02,T/R3 为03,T/R4为04,FF为全局广播。 3,地址:为各个受控设备物理地址。如果全局广播就为FF。 4,命令:00为CCU查询各个终端。01为各个终端回复CCU查询。02为令牌命令。 全局广播为FF。 5,数据长度,数据的长度。 6,数据,即要发送的数据。 7, 校验:两个7E之间除了校验的所有数据相加,0X55减去这个数得到的是校验值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值