STM32 CubeMx(三)外部中断和串口收发

文章目录

  • 1.外部中断
    • 1.1 中断概念
    • 1.2 STM32F4外部中断
    • 1.3 配置工程和编写代码
    • 1.4 代码分享
  • 2.阻塞式串口收发
    • 2.1 串口通信概念
    • 2.2 USB转TTL模块接线
    • 2.3 配置串口参数检查、串口引脚信息是否错误
    • 2.4代码编写及现象观察
    • 2.5重写printf和sancf函数及可能遇到的问题
  • 3.中断式串口收发
    • 3.1 在cube中开启中断。
    • 3.2 代码编写
    • 3.3 总结:使用中断方式收发的流程
  • 4.DMA串口收发
    • 4.1DMA的概念
    • 4.2在cube中开启DMA
    • 4.3代码编写
    • 4.5 代码分享

1.外部中断

1.1 中断概念

中断其实就是机器收到信号后,放下正在处理的任务,来处理你设定好的中断函数。
用我们生活中的事情来举个例子。假如你正在吃饭(当前程序),突然接到了快递员的电话让你现在下去拿快递(中断请求),你回答:“好的”(中断响应),然后暂停吃饭下去拿快递(中断处理),拿完快递上来继续吃饭(执行完中断返回执行当前程序)。

而外部中断则是外部信号引起的中断,如高电平、低电平、上升沿、下降沿等。

1.2 STM32F4外部中断

STM32F4 的每个 IO 都可以作为外部中断的中断输入口。 STM32F407 的中断控制器支持 23个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F407 的 23 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB OTG FS 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
EXTI 线 20:连接到 USB OTG HS(在 FS 中配置)唤醒事件。
EXTI 线 21:连接到 RTC 入侵和时间戳事件。
EXTI 线 22:连接到 RTC 唤醒事件。
从上面可以看出, STM32F4 供 IO 口使用的中断线只有 16 个,但是 STM32F4 的 IO 口却远远不止 16 个,那么 STM32F4 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32就这样设计, GPIO 的管教GPIOx.0~GPIOx.15(x=A,B,C,D,E, F,G,H,I)分别对应中断线 0~15。这样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、 GPIOB.0、 GPIOC.0、GPIOD.0、 GPIOE.0、 GPIOF.0、 GPIOG.0,GPIOH.0,GPIOI.0。而中断线每次只能连接到 1 个 IO口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO
跟中断线的映射关系图:
STM32 CubeMx(三)外部中断和串口收发_第1张图片

STM32 CubeMx(三)外部中断和串口收发_第2张图片

1.3 配置工程和编写代码

时钟树的配置不罗嗦了。时钟树的配置
我们要实现当按下按键KEY0时,实现灯的亮灭。将PE4设置为外部中断模式。
1) 设置 IO 口模式,触发条件,设置 IO 口与中断线的映射关系。
STM32 CubeMx(三)外部中断和串口收发_第3张图片
2) 配置中断优先级(NVIC),并使能中断。 不要忘记设置NVIC选择卡。
STM32 CubeMx(三)外部中断和串口收发_第4张图片
STM32 CubeMx(三)外部中断和串口收发_第5张图片
配置完成后,就可以生成工程了。
3) 编写中断处理回调函数 HAL_GPIO_EXTI_Callback

uint16_t A=0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==GPIO_PIN_SET)
	{
		A=2;
		HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);
	}
	else if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_4)==GPIO_PIN_RESET)
	{
		A=3;
		HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);
	}
}

1.4 代码分享

CubeMx外部中断代码
提取码:tkcq

2.阻塞式串口收发

2.1 串口通信概念

串口通信是一种通信协议,通信协议就是通信双方在数据传输过程中共同遵守的协定,数据的发送方按照某种协议把数据调制成可以被传输的信号,接收方就可以使用相同的协议,从信号中解析出数据。
本人是按照这个视频配置的串口通信

2.2 USB转TTL模块接线

这里我们选择串口2。并用USB转TTL接口来与电脑进行通信。
STM32 CubeMx(三)外部中断和串口收发_第6张图片
连线如下:

USE TO TTL STM32
3.3V/5V 3.3V/5V
GND GND
RX TX
TX RX

VCC不接,3.3和5V只需接一个即可。
打开串口2,找到RX,TX对应的引脚。

2.3 配置串口参数检查、串口引脚信息是否错误

STM32 CubeMx(三)外部中断和串口收发_第7张图片检查GPIO Settiings,是否为对应的引脚。STM32 CubeMx(三)外部中断和串口收发_第8张图片
基础配置完成后,生成代码。

2.4代码编写及现象观察

在while中加入如下代码:

HAL_UART_Transmit(&huart2,(uint8_t*)"Hello! ",12,0xFFFF);
//通道句柄,传输信息,传输字长,传输时间
HAL_Delay(1000);

打开串口调试助手,注意波特率要设置一致,我都选择115200bit/s。
STM32 CubeMx(三)外部中断和串口收发_第9张图片

2.5重写printf和sancf函数及可能遇到的问题

重写pintf函数:

int fputc(int c,FILE *stream)
{
	uint8_t ch[1]={c};
	HAL_UART_Transmit(&huart2,ch,1,0xFFFF);
	return c;
}
while (1)
{
	printf("Hello %d\r\n",123);
	HAL_Delay(1000);
}

重写scanff函数:

int fgetc(FILE *stream)
{
	uint8_t ch[1];
	HAL_UART_Receive(&huart2,ch,1,0xFFFF);
	return ch[0];
}
while (1)
{
		int val=0;
		scanf("%d",&val);
		printf("%d\n",val);	
}	

关于重写函数时,可能出现的小问题。
如果程序死在了printf上,可以使用 use MicroLIB(微库),在魔术棒 / Targer 选项页中勾选use MicroLIB。

3.中断式串口收发

3.1 在cube中开启中断。

进入NVIC选项卡,使能中断,调整优先级,生成代码。
STM32 CubeMx(三)外部中断和串口收发_第10张图片

3.2 代码编写

uint8_t Buffer[5];

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{

}
HAL_UART_Transmit_IT(&huart2,buf,3);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
		HAL_UART_Transmit_IT(&huart2,buf,3);//把接收到的数据发送回去
		HAL_UART_Receive_IT(&huart2,buf,3);//再开启下一次的接收
}
HAL_UART_Receive_IT(&huart2,buf,3);

每发送和接收一个字节都会进入中断。

3.3 总结:使用中断方式收发的流程

1.调用函数开启一次中断收发的流程。
2.每发送或接收到一个字节会进入中断,由HAL进行处理,用户程序无需参与。
3.传输完指定数量的字节后HAL调用发送或接收完成回调函数。

4.DMA串口收发

4.1DMA的概念

DirectMemoryAccess(存储器直接访问)是指一种高速的数据传输操作,允许在外部设备和存储器之间直接读写数据,既不通过CPU,也不需要CPU干预。整个数据传输操作在一个称为“DMA控制器”的控制下进行。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中还可以进行其他的工作。这样,在大部分时间里,CPU和输入输出都处于并行操作,因此使整个计算机系统的效率大大提高。

4.2在cube中开启DMA

STM32 CubeMx(三)外部中断和串口收发_第11张图片

4.3代码编写

uint8_t Buffer[5];

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
		HAL_UART_Transmit_DMA(&huart2,buf,3);	
		HAL_UART_Receive_DMA(&huart2,buf,3);
}
HAL_UART_Receive_DMA(&huart2,buf,3);

但当我们发送不定长字符时,会遇到数据溢出或者数据长度不够无法返回的错误。因此我们选择不定长输入的空闲中断代码。

/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart2, buffer,3);
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
/* USER CODE END 2 */

并在串口中断函数中,编写空闲中断代码。

extern uint8_t Buffer[5];

void USART1_ IRQHandler(void)
/* USER CODE BEGIN USART1_ IRQn日*/
if(_HAL_UART_GET_FLAG(&huart2,UART_ FLAG_ IDLE) != RESET)//触发空闲中断
{
	_HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除空闲中断标志位
	HAL_UART_DMAStop(&huart2);//停止发送
	uint8_t len=3-_HAL_DMA_GET_COUNTER(huart2.hdmarx);//计算接收到了多少字节
	HAL_UART_Transmit_DMA(&huart2,buffer,len);// 把接收到的数据发送出去
	HAL_UART_Receive_DMA(&huart2,buffer,3);//开启DMA,准备下次接收
}
/* USER CODE END USART1_ IRQn日*/

4.5 代码分享

串口相关代码
提取码:nj4z

你可能感兴趣的:(STM32CubeMx,stm32,单片机,嵌入式)