1.cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断。(本文只介绍60个外部可屏蔽中断)
2.stm32只有84个中断,包括16个内核中断和68个可屏蔽中断
3.stm32f103上只有60个可屏蔽中断,f107上才有68个中断
4.先占优先级也就是抢占优先级,概念等同于51单片机中的中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断 先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。
次占优先级,也就是响应优先级,只在同一先占优先级的中断同时触发时起作用,先占优先级相同,则优先执行次占优先级较高的中断。次占优先级不会造成中断嵌套。 如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断。
5.NVIC是什么?
嵌套向量中断控制器;用于为中断分组,从而分配抢占优先级和响应优先级;
分组的方式有两种:
(1).Cortex-m3内核提供了一种3位宽度的PRIGROUP数据区,用于指示一个8位数据序列中的小数点的位置,从而表示中断优先级的分组。见下表:
(2).而实际上STM32并没有用到这么多中断,所以在分组上只分了5个组,并且表示方法有所不同;见下表:
中断示意图如图所示:
用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
根据题目要求高电平亮灯,所以设计PB9接开关,PA5接LED。
因为是高电平触发,所以设计上升沿触发,即按键按下读高电平,按键释放读低电平。
对于CubeMX的介绍和新建工程参考我之前的博客: stm32CubeMX的安装和点亮流水灯
将PA5设置为GPIO_Output,将PB9设置成GPIO_EXIT
因为我们在右图配置了管脚,所以在左侧System Core对应的各项管脚已经设置好,例如PB9和PA5对应的如图:
同样不要忘记在SYS内设置成Serial Wire
在RCC设置成Crystal/Ceramic Resonator
根据个人需要进行配置,本实验根据题目要求不需要设置,如图所示:
根据我们上次实验的说明,这里同样进行这样设置,然后生成工程:
打开Keil工程,在Drivers/STM32F1xx_HAL_Driver下找到gpio.c文件,打开找到中断服务函数,
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
在第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);//翻转PA5状态
}
}
编译检查发现有错,原来是因为我们这里使用了switch_interrupt_Pin
没有定义,所以我们先进入main.h文件添加如下代码:
/* USER CODE BEGIN Private defines */
#define switch_interrupt_Pin GPIO_PIN_9
#define switch_interrupt_GPIO_Port GPIOB
#define switch_interrupt_EXTI_IRQn EXTI9_5_IRQn
/* USER CODE END Private defines */
这回我们再次编译查看:
发现没有错误,所以我们就可以进行烧录了。
烧录成功下面我们连接电路测试。
具体的电路连接根据我上面提到的题目分析自行连接。
测试结果如下:
完成一个STM32的USART串口通讯程序,要求:
1)设置波特率为115200,1位停止位,无校验位;
2)STM32系统给上位机(win10)连续发送“hello windows!”。win10采用“串口助手”工具接收。
根据题目要求和上次实验的经验,我们这次同样在CubeMX中进行设置
在点击NVIC Settings中勾选使能,此时就可以在右侧预览中看到已经分配了PA9和PA10管脚为输入输出。
但此时看到我们设置的另外两个管脚为黄色表示不可用,这是因为我们的时钟源没有设置。
首先我们要在main.c和usart.c中添加头文件#include "stdio.h"进行调用。
关于stdio.h文件的内容可以在文件夹内查看。
/* USER CODE BEGIN 1 */
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#if 1
//#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0x0001);
return ch;
}
#endif
/* USER CODE END 1 */
可以看到这里我们只要是重新定义了fputc函数。
我们首先在循环中添加一段数据主体,即我们的实验内容,不断发送Hello Windows,
/* USER CODE END WHILE */
printf("Hello windows!\r\n");
HAL_Delay(500);
/* USER CODE BEGIN 3 */
可以看到主函数体循环的内容是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下部添加中断回调函数。
/**
* @brief Rx Transfer completed callbacks.
* @param huart pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @retval None
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/
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); //再开启接收中断
}
验证确实能正确接收,在键盘输入一串字符会开启中断,过后重新开始发送hello windows
中断系统
STM32的NVIC和中断的总结