一、STM32中断
1.中断含义
中断即为一个突发的任务打断了正在进行的任务。
中断分为两类:
①.系统中断,体现在内核。
②.外部中断,体现在外设。
2.中断作用
跟据中断的定义,我们可以通过中断使处理器转而去优先运行正常控制流之外的代码。当中断信号达到肘, CPU 必须停止它当前正在做的事情,并且切换到一个另一个活动。为了做到这就要在内核态堆钱保存程序计数器的当前值 (寄存器的内容) ,并把与中断类型相关的地址放进程序计数量。
① 中断发生:当 CPU 在处理某一事件A时,发生了另一事件 B,请求 CPU 迅速去处理。
② 中断处理:CPU 暂停当前的工作,转去处理事件 B。
③ 中断返回:当 CPU 将事件 B 处理完毕后,再回到事件 A 中被暂停的地方继续处理事件 A。
3.中断优先级
中断允许嵌套,不同的中断有不同的优先级,处理器根据不同中断的重要程序设置不同的优先等级。
不同优先级中断的处理原则是:高级中断可以打断低级中断;低级中断不能打断高级中断。
二、STM32CubeMX点灯
1.设计思路
上拉式按键:
按键按下(接低电平),引脚 PB6 读到低电平
按键释放(接高电平),引脚 PB6 读到高电平
触发方式:
按键按下瞬间,形成下降沿
按键释放瞬间,形成上升沿
2.建立工程
按照常规选择芯片到达当前页面。
将PB6管脚的引脚模式设置为输出模式:GPIO_Output。将作为LED的引脚。
将PA2管脚的引脚模式设置为外部中断:GPIO_EXTI2。
接着我们自定义我们所选择的管脚的名称。同时PA2管脚我们要选择上升沿触发的触发方式:External Interrupt Mode with Rising edge trigger detection。
选择对应的外部中断线,点击Enabled。
配置中断的优先级。
这里用默认的。
设置时钟,设置36M。
然后生成工程文件。
3.编写代码
打开我们生成的文件,找到stm32f1xx_hal_gpio.c。
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)函数就是我们的中断服务函数,捕获到上升沿,触发中断,进入函数接着执行下面的HAL_GPIO_EXTI_Callback(GPIO_Pin)函数,这个函数是回调函数,可以发现前面有个weak。( __weak 表示此函数为虚函数,需要用户重写。)
然后进入main.c文件,进行重写,在主函数的下方。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if( GPIO_Pin == A2_EXTI_Pin)//判断外部中断源
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);//翻转LED状态
}
}
4.烧录运行
编译成功后我们烧录进我们的芯片。
点灯
三、中断方式下的串口通信
1.建立工程
首先设置rcc,添加外部时钟HSE和选择外部时钟源:
接着设置串口,点击USART1,设置MODE为异步通信,基础参数我们选择波特率为115200 Bits/s。传输数据长度为8Bit。奇偶检验无,停止位1,接收和发送都选择使能,然后GPIO引脚设置 USART1_RX/USART_TX(会自动设置),在NVIC Settings 一栏使能接收中断,这样就完成了。
然后我们进行时钟设置:
同上生成keil文件。
2.编写代码
首先我们要设置printf函数。
在main.c和usart.c中添加头文件#include “stdio.h”
在usart.c中,进行重定义,添加下面的代码:
/* 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 */
在main.c中添加我们的发送数据:
/* USER CODE END WHILE */
printf("Hello windows!\r\n");
HAL_Delay(500);
/* USER CODE BEGIN 3 */
再在main.c中加上下面的定义,用以接收串口数据:
uint8_t aRxBuffer; //接收中断缓冲
uint8_t Uart1_RxBuff[256]; //接收缓冲
uint8_t Uart1_Rx_Cnt = 0; //接收缓冲计数
uint8_t cAlmStr[] = "数据溢出(大于256)\r\n";
添加开启接收中断的语句:
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, (uint8_t *)&aRxBuffer, 1);
/* USER CODE END 2 */
在main.c下添加中断回调函数:
/* USER CODE BEGIN 4 */
/**
* @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); //再开启接收中断
}
/* USER CODE END 4 */
3.烧录运行
烧录过程:
四、DAM
1.DMA定义
直接存储器存取(Direct Memory Access,DMA)是计算机科学中的一种内存访问技术。它允许某些电脑内部的硬体子系统(电脑外设),可以独立地直接读写系统存储器,而不需绕道 CPU。在同等程度的CPU负担下,DMA是一种快速的数据传送方式。它允许不同速度的硬件装置来沟通,而不需要依于 CPU的大量中断请求。
2.DMA数据传输方式
普通模式:
传输结束后(即要传输数据的数量达到零),将不再产生 DMA 操作。若开始新的 DMA 传输,需在关闭 DMA 通道情况下,重新启动 DMA 传输。
循环模式:
可用于处理环形缓冲区和连续数据流(例如 ADC 扫描模式)。当激活循环模式后,每轮传输结束时,要传输的数据数量将自动用设置的初始值进行加载, 并继续响应 DMA 请求。
3.新建工程
还是常规的新建工程,找到我们的STM32F103C8T6芯片。
设置RCC
然后设置usart串口
设置使能中断
接着就要开始DMA设置了,我们要设置到中速medium,然后下面的模式为normal,右边点击选择memory。
回到system core去设置DMA
时钟设置
然后生成keil文件,进行代码编辑。
4.编写代码
在main.c中添加代码
uint8_t Senbuff[] = "Hello world!"; //定义数据发送数组
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Senbuff, sizeof(Senbuff));
HAL_Delay(1000);
5.烧录运行
烧录过程
五、总结
此次实验使用两种不同的中断方式,感觉在MX中设置好DMA后,代码的编写简单点,也不添加头文件,有了收获。