嘿!我是目录
一、文章内容提示
学习stm32中断、DMA通信原理和编程方法。使用stm32tubemx和HAL库分别完成以下编程练习:
- 用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
- 采用串口中断方式重做上次的串口通信:一个STM32的USART串口通信程序(汇编)。
- STM32采用串口DMA方式,用115200bps或更高速率向上位机连续发送数据。
二、STM32中断
2.1 中断概念
- 中断:
CPU执行程序时,由于发生了某种随机的事件(外部或内部),引起CPU暂时中断正在运行的程序,转去执行一段特殊的服务程序(中断服务子程序或中断处理程序),以处理该事件,该事件处理完后又返回被中断的程序继续执行,这一过程称为中断。引发中断的称为中断源。
比如:看电视时突然门铃响,那么门铃响就相当于中断源。有些中断还能够被其他高优先级的中断所中断,那么这种情况又叫做中断的嵌套。
STM32F10x芯片有84个中断通道,包括 16 个内核中断和 68 个可屏蔽中断,这些中断通道已按照不同优先级顺序固定分配给相应的外部设备。
- 抢占优先级:高抢占式优先级的中断事件会打断当前的主程序/中断程序的运行。中断嵌套。
- 响应优先级:在抢占式优先级相同的情况下,高响应优先级的中断优先被响应。不能嵌套,只能等待低响应优先级中断执行完成才能得到响应。
- 规则:先抢占优先级,后响应优先级;抢占式优先级决定是否会有中断嵌套。
2.2 NVIC介绍
NVIC英文全称是Nested Vectored Interrupt Controller:中文意思就是嵌套向量中断控制器,它属于M3内核的一个外设,控制着芯片的 中断相关功能。由于ARM给NVIC预留了非常多的功能,但对于使用M3内核设计芯片的公司可能就不需要这么多功能,于是就需要在NVIC上裁剪。ST公司的STM32F103芯片内部中断数量就是NVIC裁剪后的结果。 中断控制相关寄存器在固件库core_cm3.h文件NVIC结构体内。可打开任意库函数工程即可查看到。
2.3 中断优先级
- STM32F103芯片支持60个可屏蔽中断通道,每个中断通道都具备自己的中断优先级控制字节(8位,但是STM32F103中只使用4位,高4位有效),用于表达优先级的高4位又被为组成抢占式优先级和响应
- 优先级:通常也把响应优先级称为“亚优先级”或“副优先级”,每个中断源都需要被指定这两种优先级。 高抢占式优先级的中断事件会打断当前的主程序或者中断程序运行,俗称中断嵌套。在抢占式优先级相同的情况下,高响应优先级的中断优先被响应。 当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理那一个。
三、高低电平控制控制LED灯亮和灭
3.1 步骤
- 新建项目
- 选择STM32F103C8,后续按图示即可
到这一部分,操作到和图示一致。
3.2 加入代码
在Keil打开的项目里找到 main.c
打开,加入以下代码:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
GPIO_PinState b0_pin = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); // 读取b0的状态
b0_pin=1-b0_pin;
switch (GPIO_Pin){
//判断引脚
case GPIO_PIN_0:
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,1-b0_pin); // 将a1写入与b0相同的电位
break;
}
}
注意代码加在main函数外面。
3.3 烧录
- 用串口调试助手烧录即可。
3.4 实验结果
因视频太大,所以剪辑了一下,实际显示可能稍有出入;
中断是:GPIOB端口一引脚接一个开关(用杜邦线模拟代替),即用杜邦线连接断开,此处未拍出。
四、串口通信
4.1 步骤
步骤和前面的一致,但有不一样的地方参考下面图示。
- 在设置完SYS和RCC后,设置下图所示:
- 设置完后面想应的后,重新命名项目,及保存路径,将CodeGenerator设置后,GENERATE CODE,然后open project在Keil里打开。
4.2 加入代码
- 在keil5里打开项目,进入main.c文件,在里面定义如下数据,注意不是在main函数里,而是在头文件后:
uint8_t aRxBuffer;//接收缓冲中断
uint8_t Uart1_RxBuff[256];//接收缓冲
uint8_t Uart1_Rx_Cnt=0;//接收缓冲计数
uint8_t cAlmStr[]="数据溢出(大于256)";
- 在main.c里添加,注意不是加在main函数里
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *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); //再开启接收中断
}
- 在main函数里,最后面添加:
//接收中断函数
HAL_UART_Receive_IT(&huart1,(uint8_t*)&aRxBuffer,1);
4.3 实验结果
- 连接串口,烧录
- 通过串口助手发送消息,显示:
注意:
烧录时Boot0要置1;
调试时串口置0。
小小的总结
- 设置了中断之后,在回调函数里写入我们想要实现功能,当我们触发中断的时候,就会实现功能。
- 用STM32CubeMX来代替写代码特别方便,只需要写入一些我们想要的函数即可。
- 烧录时还是要注意器件的连接问题,接触不良就会烧录不成功,其次一定要注意Boot0置1和置0,不然就不能完成实验。