目录
概述
本文主要是使用AT32F403A开发板,基于V2库串口1 RDBF中断接收数据功能,并且使用串口空闲中断(IDLE)来接收完整的一帧数据,同时把上一章的printf加入,都是使用串口1来做。
串口工具使用的Atlink-ez自带的串口功能。
工程建立、调试工具配置在前面章节有详细介绍。
硬件
硬件方面使用的是参考官方AT32F437 SURF板子而设计的一个AT32F403A开发板,板子上的芯片是AT32F403AVGT7的型号,开发板上面还板载了一个atlink-ez的仿真器,atlink-ez除了可以在线仿真和下载之外还有一个串口的功能,硬件上是通过跳线帽接到了MCU的串口1,pa9/10上面。
如下图是开发板pcb图,以及硬件资源。(左边上角的就是atlink-ez,用usb线接到pc即可):
如下是实物图:
本章的主要内容是使用串口1的中断进行数据的收发,相关原理图部分(jp1的1和2,3和4,分别用跳线帽接起来):
软件
软件上主流程是串口1使用RDBF中断来接收数据,并且使用串口空闲中断(IDLE)来判定接收的是完整的一帧数据,然后再通过轮询方式把这一帧的数据发送轮询方式一个字节一个字的出来。Printf重映射的最低层其实也是使用的串口的轮询的方式发送出来的。
串口的初始化包括gpio的初始化以及串口的初始化,串口1使用默认的IO,PA9/PA10。一般当IO作为外设输出的时候设置为复用推挽输出功能,输入的设置为浮空输入或者上下拉输入模式。
如图是IO的分布:
软件上配置串口1的波特率为115200,数据位8位,停止位1位,开启接收中断(RDBF)和空闲中断(IDLE),开启中断后,需要对中断服务函数进行编写,中断服务函数的名称是固定的,需要添加内容,开启中断后一定要记得在对应中断里面添加清除中断标志位,不清除的就会一直在响应中断了,导致程序异常。
串口配置:
/*
*串口1 配置函数
*IO:PA9/PA10
*blound: 波特率
*数据位 8,停止位 1,无校验
*/
void usart1_init(u32 bound)
{
gpio_init_type gpio_init_struct;
/*Enable the UART Clock*/
crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE); //开启GPIOA的时钟
crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE); //开启USART1的时钟
gpio_default_para_init(&gpio_init_struct);
/* Configure the UART1 TX 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_9; //PA9
gpio_init_struct.gpio_pull = GPIO_PULL_NONE; //无上下拉
gpio_init(GPIOA, &gpio_init_struct);
/* Configure the UART1 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_INPUT; //输入模式
gpio_init_struct.gpio_pins = GPIO_PINS_10; //PA10
gpio_init_struct.gpio_pull = GPIO_PULL_UP; //上拉
gpio_init(GPIOA, &gpio_init_struct);
nvic_irq_enable(USART1_IRQn, 0, 0); //使能串口1中断,优先级0,次优先级0
/*Configure UART param*/
usart_init(USART1, bound, USART_DATA_8BITS, USART_STOP_1_BIT); //波特率,8数据位,1停止位
usart_hardware_flow_control_set(USART1,USART_HARDWARE_FLOW_NONE); //无硬件流操作
usart_parity_selection_config(USART1,USART_PARITY_NONE); //无校验
usart_transmitter_enable(USART1, TRUE); //使能发送
usart_receiver_enable(USART1, TRUE); //使能接收
usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE); //使能串口接收中断
usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE); //使能串口空闲中断
usart_enable(USART1, TRUE); //使能串口
}
定义一个串口接收和发送数据结构体,便于扩展其他的串口。
定义一个串口接收和发送数据结构体,便于扩展其他的串口实验。
struct Muart {
u8 Uartrxbuf[USART_REC_LEN]; //接收buf
u8 Uarttxbuf[USART_REC_LEN]; //发送buf
u8 Uartrxsta; //接收状态
u16 Uartrxcut; //接收数据计数(长度)
u16 Uarttxcut; //发送数据长度
};
中断服务函数:
串口的RDBF中断可以通过软件去读取数据寄存器来清除中断标志位,这里我们在获取数据的时候就正好是读取数据寄存器,正好清除了RDBF中断标志位,所以不需要使用usart_flag_clear函数来清除标志位;串口的IDLE中断可以通过读取串口的状态寄存器然后再读取数据寄存器来清除。
void USART1_IRQHandler(void)
{
uint8_t clear;
if(usart_flag_get(USART1, USART_RDBF_FLAG) != RESET) // USART1接收中断响应
{
Muartnum[0].Uartrxbuf[Muartnum[0].Uartrxcut++] =USART1->dt; // USART1读取数据寄存器
}
if(usart_flag_get(USART1, USART_IDLEF_FLAG) != RESET) // USART1总线空闲
{
clear=USART1->sts; // USART1清除空闲中断标志位
clear=USART1->dt; // USART1清除空闲中断标志位
clear&=0;
Muartnum[0].Uartrxsta = 1; // USART1接收完成标志位
}
}
轮询发送函数
void usart1_txdatas(u8 *SendData,u16 len)
{
u16 i=0;
for(i=0;i<len;i++)
{
while(usart_flag_get(USART1 , USART_TDBE_FLAG) == RESET); //发送寄存器空
usart_data_transmit(USART1, SendData[i]); //发生数据
while(usart_flag_get(USART1, USART_TDC_FLAG) == RESET); //发生完成
}
}
测试结果:
测试代码:
通过串口往板子发送数据,正常的话会收到相同的数据,经过测试,功能正常。
最后
有问题的可以加QQ群交流,同时相关代码上传到QQ群中。