1、编写UART_2串口发送程序时,初始化需要设置哪些参数?
1)确定MCU串口号、所接MCU的引脚:
采用的串口为UART_2,在user.h中宏定义使用的串口名为UART_User,以便增强编程的可移植性 UART2串口对应的引脚为PTA2(发送TX)、PTA3(接收RX)
2)确定串口UART_User的波特率,在main.c中,对其初始化
-
假设波特率为115200:
uart_init(UART_User,115200); //初始化串口模块
3)printf的设置:格式化输出函数printf灵活地从串口输出调试信息
-
在printf头文件中宏定义需要与printf相关联的调试串口号
#define UART_printf UART_2 //printf函数使用的串口号
2、假设速度为115200,系统时钟为72MHz,波特率寄存器 BRR中的值应该是多少?
波特率 :115200
SystemCoreClock = 72MHz
根据以下代码进行计算波特率寄存器 BRR 中的值:
//配置波特率
if(*uart_cr1&(0x1UL<<15) == (0x1UL<<15))
usartdiv = (uint16_t)((SystemCoreClock/115200)*2);
else
usartdiv = (uint16_t)((SystemCoreClock/115200));
*uart_brr = usartdiv;
需要考虑 OVER8 模式和非 OVER8 模式的情况:
对于 OVER8 模式:
usartdiv = (uint16_t)((SystemCoreClock / 115200) * 2);usartdiv = (uint16_t)((72000000 / 115200) * 2) = (uint16_t)(625.0 * 2) = 1250
对于非 OVER8 模式:
usartdiv = (uint16_t)(SystemCoreClock / 115200);usartdiv = (uint16_t)(72000000 / 115200) = (uint16_t)(625.0) = 625
根据不同的模式,波特率寄存器 BRR 中的值应分别为 1250(OVER8 模式)和 625(非 OVER8 模式)
3、中断向量表在哪个文件中?表中有多少项?给出部分截图。
中断向量表存放在 03_MCU/startup/startup_stm32|431rctx.s 中
- 表中共有99个中断,前16个为内核中断,后面的为非内核中断
4、以下是中断源使能函数,假设中断源为TIM6,将函数实例化(写出各项具体数值)。
函数传入参数为IRQn(中断号),因为中断源为TIM6,查表可知
TIM6对应接受中断的IRQ号为54,54≥0进入if{}
ISER[(((uint32_t)IRQn) >> 5UL)]函数内部实现将IRQ号值右移5位
- 54>>5=1 , 索引值为1
(uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL))确定要设置的位数
- 54 & 0x1F = 22 , 第22位
简化计算: 54/32=1…22
则将ISER[1]的第22位设置为1
5、假设将UART_2和TIM6交换其在中断向量表中的位置和IRQ号,UART_2可以正常中断吗?
假设将 UART_2 和 TIM6 在中断向量表中的位置和 IRQ 号交换:
UART_2 的中断号将变为 TIM6 的原始中断号—54
TIM6 的中断号将变为 UART_2 的原始中断号—38
如果 UART_2 原本可以正常中断,并且在交换后,其新的中断号没有被其他设备占用,那么 UART_2 仍然可以正常中断。
因为中断号的改变不影响中断控制器 NVIC 的配置,只是改变了中断向量表中的中断函数入口地址。
但是需要注意的是,如果在交换后,新的中断号被其他设备占用,或者相关的中断配置没有正确更新,那么 UART_2 的中断功能可能会受到影响。因此,在进行中断号交换时,需要确保相关的中断配置和中断处理函数都正确更新。
6、实现UART_2串口的接收程序
当收到字符时:
① 在电脑的输出窗口显示下一个字符,如收到A显示B;
② 亮灯:
收到字符G,亮绿灯;
收到字符R,亮红灯;
收到字符B,亮蓝灯;
收到其他字符,不亮灯。
实现方式:
(1) 用构件调用方式实现
- 核心代码:
//接收字符
ch = uart_re1(UART_User,&flag);
//若接收到字符flag为1,未接收到则为0
if(flag){
//收到字符时的处理
switch(ch){
case 'G':
gpio_set(LIGHT_GREEN,LIGHT_ON); //亮绿灯
gpio_set(LIGHT_RED,LIGHT_OFF); // 关闭红灯
gpio_set(LIGHT_BLUE,LIGHT_OFF); // 关闭蓝灯
break;
case 'R':
gpio_set(LIGHT_RED,LIGHT_ON); // 亮红灯
gpio_set(LIGHT_GREEN,LIGHT_OFF); // 关闭绿灯
gpio_set(LIGHT_BLUE,LIGHT_OFF); // 关闭蓝灯
break;
case 'B':
gpio_set(LIGHT_BLUE,LIGHT_ON); // 亮蓝灯
gpio_set(LIGHT_RED,LIGHT_OFF); // 关闭红灯
gpio_set(LIGHT_GREEN,LIGHT_OFF); // 关闭绿灯
break;
default:
gpio_set(LIGHT_RED,LIGHT_OFF); // 关闭红灯
gpio_set(LIGHT_GREEN,LIGHT_OFF); // 关闭绿灯
gpio_set(LIGHT_BLUE,LIGHT_OFF); // 关闭蓝灯
break;
}
printf("%c\n",ch+1);//显示下一个字符
}
}
(2) UART部分用直接地址方式实现(即不调用uart.c中的函数,其他部分如GPIO、中断设置可调用函数)
- 核心代码:
for(;;)
{
// 判断接收缓冲区是否满,接受字符
if (*uart_isr & (0x1UL << 5U)) {
// 读取接收到的字符
received_char = (uint8_t)(*uart_rdr & 0xFF);
// 接收到字符时的处理
switch (received_char) {
case 'G':
gpio_set(LIGHT_GREEN, LIGHT_ON); // 亮绿灯
gpio_set(LIGHT_RED, LIGHT_OFF); // 关闭红灯
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭蓝灯
printf("接收:%c【绿灯】\n",received_char);
break;
case 'R':
gpio_set(LIGHT_RED, LIGHT_ON); // 亮红灯
gpio_set(LIGHT_GREEN, LIGHT_OFF); // 关闭绿灯
gpio_set(LIGHT_BLUE, LIGHT_OFF); // 关闭蓝灯
printf("接收:%c【红灯】\n",received_char);
break;
case 'B':
gpio_set(LIGHT_BLUE, LIGHT_ON); // 亮蓝灯
gpio_set(LIGHT_RED, LIGHT_OFF); // 关闭红灯
gpio_set(LIGHT_GREEN, LIGHT_OFF); // 关闭绿灯
printf("接收:%c【蓝灯】\n",received_char);
break;
default:
// 收到其他字符不亮灯
gpio_set(LIGHT_RED, LIGHT_OFF);
gpio_set(LIGHT_GREEN, LIGHT_OFF);
gpio_set(LIGHT_BLUE, LIGHT_OFF);
printf("接收:%c【不亮灯】\n",received_char);
break;
}
printf("显示:%c\n",received_char+1);
}
}