一、stm32中断实验
中断原理
中断请求:外部设备或者内部模块产生中断请求信号,向微控制器发出中断请求。
中断控制器:STM32微控制器内部包含中断控制器,负责管理和响应各种中断请求。
中断向量表:在中断控制器中有一个中断向量表,存储了每个中断源对应的中断服务程序的地址。
中断处理:当中断请求到达时,中断控制器会根据中断源的优先级确定要执行的中断服务程序的地址,并跳转到该地址执行中断处理程序。
中断服务程序:中断服务程序是用户编写的处理中断事件的代码,用于响应特定的中断请求,处理中断事件。
中断结束:中断服务程序执行完成后,会通过特定的指令将控制返回给原来的程序,继续执行之前被中断的代码。
要求
用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。如果完成后,尝试在main函数while循环中加入一个串口每隔1s 发送一次字符的代码片段,观察按键中断对串口发送是否会带来干扰或延迟。
代码示例
以下是代码实例,在主循环中同时处理按键中断和串口发送可能会引入一些延迟
#include "main.h"
#include "stm32f1xx_hal.h"
UART_HandleTypeDef huart1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Transmit(&huart1, (uint8_t *)"Initialization complete\r\n", 24, HAL_MAX_DELAY);
while (1)
{
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_SET) // 检测开关状态
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 开关高电平,LED亮
}
else
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 开关低电平,LED灭
}
HAL_Delay(1000); // 每隔1秒
HAL_UART_Transmit(&huart1, (uint8_t *)"Hello\r\n", 7, HAL_MAX_DELAY); // 串口发送字符
}
}
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_0)
{
// 处理按键中断事件
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
static void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
}
void Error_Handler(void)
{
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
二、串口中断实验
要求
当stm32接收到1个字符“s”时,停止持续发送“hello windows!”; 当接收到1个字符“t”时,持续发送“hello windows” 当stm32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”
功能需求
-
当STM32接收到字符"S"时,停止持续发送"Hello Windows!";当接收到字符"T"时,持续发送"Hello Windows!"。可以采用一个全局标量作为信号灯,在接收到相应字符时控制发送行为。
-
当STM32接收到字符"stop stm32!"时,停止持续发送"Hello Windows!";当接收到字符"go stm32!"时,持续发送"Hello Windows!"。为实现这一功能,需要将接收到的连续字符保存到一个字符数组中,并编写一个接收字符串的函数来进行判断匹配。可以参考链接中的方法,将接收到的字符逐个保存到字符数组中,然后判断是否匹配目标字符串,从而控制发送行为。
代码实例
#include "stm32f1xx.h"
#define BUFFER_SIZE 20
volatile char rx_buffer[BUFFER_SIZE];
volatile uint8_t rx_index = 0;
volatile uint8_t flag_s = 1; // 初始为1,表示可以发送
void USART1_IRQHandler(void)
{
if(USART1->SR & USART_SR_RXNE)
{
char received_char = USART1->DR;
if(flag_s && received_char == 's')
{
flag_s = 0;
}
else if(!flag_s && received_char == 't')
{
flag_s = 1;
}
// 处理接收到的字符串
rx_buffer[rx_index++] = received_char;
if(rx_index >= BUFFER_SIZE)
{
rx_index = 0;
}
// 判断接收到的字符串是否匹配目标字符串
if(strstr(rx_buffer, "stop stm32!") != NULL)
{
flag_s = 0;
}
else if(strstr(rx_buffer, "go stm32!") != NULL)
{
flag_s = 1;
}
}
}
void USART_Init(void)
{
// 初始化USART1,配置为115200波特率,8位数据位,1位停止位,无校验位
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;
USART1->BRR = 0x1A1; // 波特率为115200
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
USART1->CR1 |= USART_CR1_UE;
NVIC_EnableIRQ(USART1_IRQn);
}
void USART_SendString(char *str)
{
while(*str)
{
while(!(USART1->SR & USART_SR_TXE));
USART1->DR = *str++;
}
}
int main(void)
{
USART_Init();
while(1)
{
if(flag_s)
{
USART_SendString("Hello Windows!\r\n");
}
}
}