文章目录
- 一、中断介绍
-
- 二、CubeMX中断方式点灯
- 1.题目要求
- 2.CubeMX设置
-
- 3.代码编写
- 4.连接测试
- 三、中断方式实现串口通信
-
- 四、参考
一、中断介绍
1.基础知识
1.cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断。(本文只介绍60个外部可屏蔽中断)
2.stm32只有84个中断,包括16个内核中断和68个可屏蔽中断
3.stm32f103上只有60个可屏蔽中断,f107上才有68个中断
4.先占优先级也就是抢占优先级,概念等同于51单片机中的中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断 先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。
次占优先级,也就是响应优先级,只在同一先占优先级的中断同时触发时起作用,先占优先级相同,则优先执行次占优先级较高的中断。次占优先级不会造成中断嵌套。 如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断。
![在这里插入图片描述](https://img-blog.csdnimg.cn/61d81ed524b24b7fa3dfc006629144f9.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
5.NVIC是什么?
嵌套向量中断控制器;用于为中断分组,从而分配抢占优先级和响应优先级;
分组的方式有两种:
(1).Cortex-m3内核提供了一种3位宽度的PRIGROUP数据区,用于指示一个8位数据序列中的小数点的位置,从而表示中断优先级的分组。见下表:
![在这里插入图片描述](https://img-blog.csdnimg.cn/c79275c14a41443aaffa1d9a41f75dc2.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
(2).而实际上STM32并没有用到这么多中断,所以在分组上只分了5个组,并且表示方法有所不同;见下表:
![在这里插入图片描述](https://img-blog.csdnimg.cn/f1fa4b774f7d455195eba25b885efbab.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
中断示意图如图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/c6012fb1f620467baca3d70b7ce007a4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
2.中断向量表
![在这里插入图片描述](https://img-blog.csdnimg.cn/64217f2443214eef8568329e05be40da.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_18,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/047ecbea7fea42f8b3fce16a797ed119.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_18,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f60db2910c314500acabb53acc9506be.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_18,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/dd790148ad574aaeb2b7b21d271c4579.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_18,color_FFFFFF,t_70,g_se,x_16)
此表在stm32使用手册中有记录。
3.中断过程
![在这里插入图片描述](https://img-blog.csdnimg.cn/dca3e4d3d83b4fada0365b72be4eec4b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/bcfb997b62fd4714bdeab750f14a3796.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
二、CubeMX中断方式点灯
1.题目要求
用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
根据题目要求高电平亮灯,所以设计PB9接开关,PA5接LED。
因为是高电平触发,所以设计上升沿触发,即按键按下读高电平,按键释放读低电平。
2.CubeMX设置
对于CubeMX的介绍和新建工程参考我之前的博客: stm32CubeMX的安装和点亮流水灯
设置管脚
![请添加图片描述](https://img-blog.csdnimg.cn/724afe27c99a49488c45d2e921800e8a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
将PA5设置为GPIO_Output,将PB9设置成GPIO_EXIT
因为我们在右图配置了管脚,所以在左侧System Core对应的各项管脚已经设置好,例如PB9和PA5对应的如图:
![请添加图片描述](https://img-blog.csdnimg.cn/1b144106ef3240b78c92d332c1b77665.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
![请添加图片描述](https://img-blog.csdnimg.cn/34e182ec68d544059453b62db10c8f48.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
同样不要忘记在SYS内设置成Serial Wire
![请添加图片描述](https://img-blog.csdnimg.cn/936ad99807bc481fb198a5298ca03648.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
在RCC设置成Crystal/Ceramic Resonator
![在这里插入图片描述](https://img-blog.csdnimg.cn/ac6229a8cf5041a88051ff7e1fed32a4.png)
设置时钟源
根据个人的需要设置时钟源,这里我设置成72MHz
![请添加图片描述](https://img-blog.csdnimg.cn/0c1c449ce97d4e3cbee16ed97760fa5b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
配置时钟优先级
根据个人需要进行配置,本实验根据题目要求不需要设置,如图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/d8f992b4417d46ec97e961827b3063a9.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
生成工程
根据我们上次实验的说明,这里同样进行这样设置,然后生成工程:
![请添加图片描述](https://img-blog.csdnimg.cn/54ff088e62034fb5acad28e2faf6c397.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
3.代码编写
打开Keil工程,在Drivers/STM32F1xx_HAL_Driver下找到gpio.c文件,打开找到中断服务函数,
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2041857349e24052b4dabefce68a92c8.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
在第561行看到此函数是个weak函数需要我们在别处重新书写。
所以我们在main函数内写入,
打开main.c文件,在main内找个地方编写如下代码:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if( GPIO_Pin == switch_interrupt_Pin)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
编译检查发现有错,原来是因为我们这里使用了switch_interrupt_Pin
没有定义,所以我们先进入main.h文件添加如下代码:
#define switch_interrupt_Pin GPIO_PIN_9
#define switch_interrupt_GPIO_Port GPIOB
#define switch_interrupt_EXTI_IRQn EXTI9_5_IRQn
这回我们再次编译查看:
![在这里插入图片描述](https://img-blog.csdnimg.cn/42c4df930f5a4e499e9b362bc58463ad.png)
发现没有错误,所以我们就可以进行烧录了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/6bcf1a17a19c4a2c966f015426d1abb1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
烧录成功下面我们连接电路测试。
4.连接测试
具体的电路连接根据我上面提到的题目分析自行连接。
测试结果如下:
![请添加图片描述](https://img-blog.csdnimg.cn/e0c1ce86c5ae4a569c12244beb527814.gif)
三、中断方式实现串口通信
1.题目要求
完成一个STM32的USART串口通讯程序,要求:
1)设置波特率为115200,1位停止位,无校验位;
2)STM32系统给上位机(win10)连续发送“hello windows!”。win10采用“串口助手”工具接收。
2.工程建立
根据题目要求和上次实验的经验,我们这次同样在CubeMX中进行设置
- 串口设置
在Connectivity——USART1——Mode中选择Asynchronous,意为异步通信,此时下面默认的波特率就为115200bit,传输数据长度为8bit,各项参数可以自行查看。
![在这里插入图片描述](https://img-blog.csdnimg.cn/ef47b6b2751d4974b6adb7a07d95fbba.png)
在点击NVIC Settings中勾选使能,此时就可以在右侧预览中看到已经分配了PA9和PA10管脚为输入输出。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2badda7054b54b7799a23a46927d1c6f.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
但此时看到我们设置的另外两个管脚为黄色表示不可用,这是因为我们的时钟源没有设置。
- 时钟源设置:
在RCC中选择高速时钟源Crystal/Ceramic Resonator并在Clock Configuration中选择72Mhz
![在这里插入图片描述](https://img-blog.csdnimg.cn/bc07adf172b046b5b666e12b6dc33b68.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
可以看到此时的预览引脚变成了绿色表示配置正确:
![请添加图片描述](https://img-blog.csdnimg.cn/94fff3946c0a4dc292918dedef8b813c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
3.代码编写
首先我们要在main.c和usart.c中添加头文件#include "stdio.h"进行调用。
关于stdio.h文件的内容可以在文件夹内查看。
- 然后我们要在usart.c中定义相关函数方便在main中的使用,下面是usart.c的编写
usart.c:
#if 1
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit(int x)
{
x = x;
}
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0x0001);
return ch;
}
#endif
可以看到这里我们只要是重新定义了fputc函数。
- 在书写完usart.c文件后我们就要对main函数进行操作,添加中断指令
我们首先在循环中添加一段数据主体,即我们的实验内容,不断发送Hello Windows,
printf("Hello windows!\r\n");
HAL_Delay(500);
可以看到主函数体循环的内容是printf输出hello windows换行,并延时500ms。
接着我们需要在main.c中添加如下定义,用来接收串口数据
uint8_t aRxBuffer;
uint8_t Uart1_RxBuff[256];
uint8_t Uart1_Rx_Cnt = 0;
uint8_t cAlmStr[] = "数据溢出(大于256)\r\n";
添加接收中断的语句,在main.c用户代码段2书写
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
然后在main.c下部添加中断回调函数。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UNUSED(huart);
if(Uart1_Rx_Cnt >= 255)
{
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
HAL_UART_Transmit(&huart1, (uint8_t *)&cAlmStr, sizeof(cAlmStr),0xFFFF);
}
else
{
Uart1_RxBuff[Uart1_Rx_Cnt++] = aRxBuffer;
if((Uart1_RxBuff[Uart1_Rx_Cnt-1] == 0x0A)&&(Uart1_RxBuff[Uart1_Rx_Cnt-2] == 0x0D))
{
HAL_UART_Transmit(&huart1, (uint8_t *)&Uart1_RxBuff, Uart1_Rx_Cnt,0xFFFF);
Uart1_Rx_Cnt = 0;
memset(Uart1_RxBuff,0x00,sizeof(Uart1_RxBuff));
}
}
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
}
- 编译执行检查有没有错误;
![在这里插入图片描述](https://img-blog.csdnimg.cn/789f4fad7ec346e79426af8aefff9062.png)
检查发现没有错误
4.烧录测试
![在这里插入图片描述](https://img-blog.csdnimg.cn/bcadb4977bba4602ad2b7705ba0a9d65.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
烧录显示一切正常,下面进行串口测试。
打开串口助手
![在这里插入图片描述](https://img-blog.csdnimg.cn/ca1cd962591140ff85ab0766b41871f6.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAY2xldmVyeW9nYQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
验证确实能正确接收,在键盘输入一串字符会开启中断,过后重新开始发送hello windows
四、参考
中断系统
STM32的NVIC和中断的总结
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)