一、HAL库下的中断
打开STM32cube ide,新建一个工程取名为led interrupt.
STM32串口通信编程
首先配置时钟为外部高速时钟源
然后设置debug模式,选用sw模式(这个模式功耗最小)
然后选用你想使用的GPIO口(注意,如果你选用之后,sys选项出现感叹号 system wake up ,这个意思是你选用的GPIO有其他作用,建议换一个GPIO口)
选用完毕之后,再修改以下这个时钟模式
生成工程之后如图所示
在HAL库下,cubeide 已经给我们写好了中断函数,但是这个函数是空的,我们需要使用中断函数的功能时就需要自己修改配置。HAL库里的中断函数名为HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_15:
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_12); //这个函数的意思是翻转A12的电平
}
break;
default: break;
}
}
这个函数可直接写如main文件中,不需要到配置文件中去修改。
注意的是,这里使用杜邦线模拟开关触发中断时,由于抖动十分严重,建议在此函数里写一个延时函数,但不能调用HAL库的Delay函数,因为Delay函数的使用需要一个外部时钟的中断实现,在HAL库里,配置的中断默认为最高级的中断,直接调用Delay 函数的话会导致进程卡死在中断函数里。
这里还有一个需要注意的点,建议设置中断触发引脚时,设置为下拉模式,不然的话悬空的引脚电平极易受到干扰,影响实验的结果
二、HAL库下的中断串口通信
很多配置和普通的中断配置差不多
只需要多配置一个usart还有一个允许异步通信的开关,详见下图
这里需要一个接收发送字符的函数,在HAL库下这个函数为
HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
这里用的是usart1 口,在本实验中此函数具体化为
HAL_UART_Receive_IT(&huart1, (uint8_t *)&a, 2);
这里的uint8_t为HAL库下自定义的数据类型,和c中的char类似都是一字节。这里是取a的地址并强制转化为指针,2是接收长度(stm32cube ide 一般默认打开overrun,允许读入溢出,多余部分被丢弃,要读入多字节的时候建议修改,这里我只需要判断一个字符,但是字符长度为一不能读入多字符,改为二就可以。)
接下来写自定义的中断处理函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(a=='g')
{
flag=1;
}
if(a=='t')
{
flag=1;
}
if(a=='s')
{
flag=0;
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&a, 1);
}
这里有一个很奇怪的点,用if else语句会导致进程异常,全用if没任何问题
接下来就是主函数
char a;
char s1[]="hello windows\n";
int flag=1;
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, (uint8_t *)&a, 1);
while (1)
{
if(flag==1)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&s1, strlen(s1),0xFFFF);
}
HAL_Delay(100);
}
这里调用了strlen函数,记得加头文件#include <string.h>
结果如下
本次实验中,注意的是接收中断HAL_UART_Receive_IT,需要接收可变多字节的时候建议重写这个函数。
三、DMA
DMA用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。
DMA传输方式
DMA的作用就是实现数据的直接传输,而去掉了传统数据传输需要CPU寄存器参与的环节。
这里使用DMA主要是用于usart的数据传输,在DMA控制表中,usart1的请求位于通道四和五,分别为
发送口和接收口
在串口通信DMA这种方式中,DMA负责传输数据到usart口,然后通过usart口发送给上位机,这其中并没有cpu的参与
DMA中断
每个DMA通道都可以在DMA传输过半、传输完成和传输错误时产生中断。为应用的灵活性考虑,通过设置寄存器的不同位来打开这些中断。
这里只对DMA简单介绍,详细内容见https://blog.csdn.net/as480133937/article/details/104827639/
现在开始建立DMA通信的工程
和之前的工程配置差不多,多的只是DMA方面的配置
点击add添加DMA关于usart的配置
注意: 如果你是在DMA设置界面添加DMA 而没有开启对应外设的话 ,默认为MENTOMEN
Channel DMA传输通道设置
DMA1 : DMA1 Channel 0~DMA1 Channel 7
DMA2: DMA2 Channel 1~DMA1 Channel 5
Dirction : DMA传输方向
四种传输方向:
外设到内存 Peripheral To Memory
内存到外设 Memory To Peripheral
内存到内存 Memory To Memory
外设到外设 Peripheral To Peripheral
Priority: 传输速度
最高优先级 Very Hight
高优先级 Hight
中等优先级 Medium
低优先级;Low
DMA传输模式
Normal:正常模式
当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
Circular: 循环模式
传输完成后又重新开始继续传输,不断循环永不停止
具体代码实现和二差不多,这里只是使用了两个DMA的函数
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&s1, strlen(s1));
这个是HAL库下使用DMA传输的函数,比usart那个传输函数少了一个时间延迟。
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,yeap,20);
这个是用来接收的函数,它同时开启了两个中断,当数据量达到指定长度时触发中断,当总线空闲,数据发送完成时触发中断。
然后就是关于串口空闲中断的回调函数了
HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
实验结果如图所示
参考博客https://blog.csdn.net/as480133937/article/details/104827639/