学习stm32中断、DMA通信原理和编程方法。使用stm32tubemx和HAL库分别完成以下编程练习:
1. 用stm32F103核心板的GPIOA端一管脚接一个LED,GPIOB端口一引脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED亮灯;接低电平时,LED灭灯。
一.创建项目
三个LED灯,初始化三个GPIO端口模拟键
选择PA3,选择GPIO-EXTI3模式;继续选择PA6,PB13为GPIO_EXTI
在Pinout&Configuration–System?core–GPIO中配置为如下模式
?配置中断优先级:在Pinout&Configuration–System?core–NVIC中使能外部中断,并配置优先级
?配置时钟:设时钟频率为72MHZ
生成项目
?二.
代码:
void?MX_GPIO_Init(void) {
??GPIO_InitTypeDef?GPIO_InitStruct?=?{0};
??/*?GPIO?Ports?Clock?Enable?*/ ??__HAL_RCC_GPIOC_CLK_ENABLE(); ??__HAL_RCC_GPIOD_CLK_ENABLE(); ??__HAL_RCC_GPIOA_CLK_ENABLE(); ??__HAL_RCC_GPIOB_CLK_ENABLE();
??/*Configure?GPIO?pin?Output?Level?*/ ??HAL_GPIO_WritePin(LED_Y_GPIO_Port,?LED_Y_Pin,?GPIO_PIN_RESET);
??/*Configure?GPIO?pin?Output?Level?*/ ??HAL_GPIO_WritePin(LED_G_GPIO_Port,?LED_G_Pin,?GPIO_PIN_RESET);
??/*Configure?GPIO?pin?Output?Level?*/ ??HAL_GPIO_WritePin(LED_R_GPIO_Port,?LED_R_Pin,?GPIO_PIN_RESET);
??/*Configure?GPIO?pin?:?PtPin?*/ ??GPIO_InitStruct.Pin?=?LED_Y_Pin; ??GPIO_InitStruct.Mode?=?GPIO_MODE_OUTPUT_PP; ??GPIO_InitStruct.Pull?=?GPIO_NOPULL; ??GPIO_InitStruct.Speed?=?GPIO_SPEED_FREQ_MEDIUM; ??HAL_GPIO_Init(LED_Y_GPIO_Port,?&GPIO_InitStruct);
??/*Configure?GPIO?pins?:?PAPin?PAPin?*/ ??GPIO_InitStruct.Pin?=?KEY1_Pin|KEY2_Pin; ??GPIO_InitStruct.Mode?=?GPIO_MODE_IT_FALLING; ??GPIO_InitStruct.Pull?=?GPIO_PULLUP; ??HAL_GPIO_Init(GPIOA,?&GPIO_InitStruct);
??/*Configure?GPIO?pin?:?PtPin?*/ ??GPIO_InitStruct.Pin?=?LED_G_Pin; ??GPIO_InitStruct.Mode?=?GPIO_MODE_OUTPUT_PP; ??GPIO_InitStruct.Pull?=?GPIO_NOPULL; ??GPIO_InitStruct.Speed?=?GPIO_SPEED_FREQ_MEDIUM; ??HAL_GPIO_Init(LED_G_GPIO_Port,?&GPIO_InitStruct);
??/*Configure?GPIO?pin?:?PtPin?*/ ??GPIO_InitStruct.Pin?=?KEY3_Pin; ??GPIO_InitStruct.Mode?=?GPIO_MODE_IT_FALLING; ??GPIO_InitStruct.Pull?=?GPIO_PULLUP; ??HAL_GPIO_Init(KEY3_GPIO_Port,?&GPIO_InitStruct);
??/*Configure?GPIO?pin?:?PtPin?*/ ??GPIO_InitStruct.Pin?=?LED_R_Pin; ??GPIO_InitStruct.Mode?=?GPIO_MODE_OUTPUT_PP; ??GPIO_InitStruct.Pull?=?GPIO_NOPULL; ??GPIO_InitStruct.Speed?=?GPIO_SPEED_FREQ_MEDIUM; ??HAL_GPIO_Init(LED_R_GPIO_Port,?&GPIO_InitStruct);
??/*?EXTI?interrupt?init*/ ??HAL_NVIC_SetPriority(EXTI3_IRQn,?0,?0); ??HAL_NVIC_EnableIRQ(EXTI3_IRQn);
??HAL_NVIC_SetPriority(EXTI9_5_IRQn,?1,?0); ??HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
??HAL_NVIC_SetPriority(EXTI15_10_IRQn,?2,?0); ??HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
}
注:这几个外部中断都使用了同一个处理函数,HAL_GPIO_EXTI_IRQHandler,通过传入不同的参数,来区分是哪一条中断线触发的中断。
在main文件中加入中断服务函数
?每次按键按下,LED电平变化一次
void?HAL_GPIO_EXTI_Callback(uint16_t?GPIO_Pin) { ??switch(GPIO_Pin) ??{ ????case?GPIO_PIN_3:? { HAL_GPIO_TogglePin(led_R_GPIO_Port,led_R_Pin); } break; ????case?GPIO_PIN_6: { ?HAL_GPIO_TogglePin(led_G_GPIO_Port,led_G_Pin);
} break; ????case?GPIO_PIN_13: { ???HAL_GPIO_TogglePin(led_Y_GPIO_Port,led_Y_Pin); } break; ????default:?break; ??} }
三.结果
烧录
??
每一次接地,中断一次
?2.?采用串口中断方式重做上周的串口通信作业,分别实现:1)当stm32接收到字符“s”时,停止持续发送“hello?windows!”;?当接收到字符“t”时,持续发送“hello?windows!”(提示:采用一个全局标量做信号灯);2)当stm32接收到字符“stop?stm32!”时,停止持续发送“hello?windows!”;?当接收到字符“go?stm32!”时,持续发送“hello?windows!”(提示:要将接收到的连续字符保存到一个字符数组里,进行判别匹配。写一个接收字符串的函数。
一.创建项目
设置串口USART1,在MODE下选择Asynchronous,在如下界面下选择中断
?二.?编写函数
1.安装CH34驱动程序:http://www.wch.cn/search?t=all&q=CH34
2.编写代码
bsp_uart.h:
void?Usart_SendByte(USART_TypeDef?*?pUSARTx,uint8_t?ch); void?USART_SendString(USART_TypeDef?*?pUSARTx,char?*str); void?delay_ms(uint16_t?delay_ms);
#ifndef?_BSP_UART_H #define?_BSP_UART_H
#include?"stm32f10x.h" //串口1-USART1 #define?DEBUG_UARTx USART1; #define?DEBUG_UART_CLK?????? RCC_APB2Periph_USART1 #define?DEBUG_UART_APBxClkCmd RCC_APB2PeriphClockCmd #define?DEBUG_UART_BAUDRATE 115200
//USART?GPIO?引脚宏定义 #define?DEBUG_USART_GPIO_CLK ??(RCC_APB2Periph_GPIOA) #define?DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd #define?DEBUG_USART_TX_GPIO_PORT GPIOA #define?DEBUG_USART_TX_GPIO_PIN???????GPIO_Pin_9 #define?DEBUG_USART_RX_GPIO_PORT GPIOA #define?DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define?DEBUG_USART_IRQ USART1_IRQn #define?DEBUG_USART_IRQHandler USART1_IRQHandler void?DEBUG_UART_Config(void);
#endif?/*_BSP_UART_H*/
bsp_uart.c:
#include?"./uart/bsp_uart.h"
void?DEBUG_UART_Config(void) { /*第一步:初始化GPIO*/ //定义GPIO对象 GPIO_InitTypeDef?GPIO_InitStructure; //定义串口对象 USART_InitTypeDef?USART_InitStructure; //打开串口GPIO的时钟 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE); //将USART?Tx(发送数据)的GPIO的配置为推挽复用模式 GPIO_InitStructure.GPIO_Pin=DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure); //将USART?Rx(接收数据)的GPIO配置为浮空输入模式 GPIO_InitStructure.GPIO_Pin=DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure);
/*第二步:配置串口的初始化结构体*/ //打开串口外设的时钟 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE); //配置波特率 USART_InitStructure.USART_BaudRate=DEBUG_USART_BAUDRATE; //配置数据字长 USART_InitStructure.USART_WordLength=USART_WordLength_8b; //配置停止位 USART_InitStructure.USART_StopBits=USART_StopBits_1; //配置校验位 USART_InitStructure.USART_Parity=USART_Parity_No; //配置硬件流控制 USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //配置工作模式,采用收发一起,即可接收数据,也可发送数据 USART_InitStructure.USART_Mode=USART_Mode_Rx?|?USART_Mode_Tx; //串口的初始化配置 USART_Init(DEBUG_USARTx,&USART_InitStructure); /*第三步:使能串口*/ USART_Cmd(DEBUG_USARTx,ENABLE); } //发送一个字节 void?Usart_SendByte(USART_TypeDef?*?pUSARTx,uint8_t?ch) { USART_SendData(pUSARTx,ch);//?发送一个字节数据到USART while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET);//?等待发送数据寄存器为空 } //发送字符串 void?USART_SendString(USART_TypeDef?*?pUSARTx,char?*str) { unsigned?int?k=0; do { Usart_SendByte(pUSARTx,*(str+k)); k++; }while(*(str+k)!='\0'); //?等待发送完成 while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET); } //微秒级的延时 void?delay_us(uint32_t?delay_s) {???? ??volatile?unsigned?int?i; ??volatile?unsigned?int?t; ??for?(i?=?0;?i?<?delay_s;?i++) ??{ ????t?=?11; ????while?(t?!=?0) ????{ ??????t--; ????} ??} } //毫秒级的延时函数
void?delay_ms(uint16_t?delay_ms) {???? ??volatile?unsigned?int?num; ??for?(num?=?0;?num?<?delay_ms;?num++) ??{ ????delay_us(1000); ??} } //配置嵌套向量中断控制器NVIC static?void?NVIC_Configuration(void) { ??NVIC_InitTypeDef?NVIC_InitStructure; ?? ??//?嵌套向量中断控制器组选择 ??NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); ?? ??//?配置USART为中断源 ??NVIC_InitStructure.NVIC_IRQChannel?=?DEBUG_USART_IRQ; ??//?抢断优先级 ??NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority?=?1; ??//?子优先级 ??NVIC_InitStructure.NVIC_IRQChannelSubPriority?=?1; ??//?使能中断 ??NVIC_InitStructure.NVIC_IRQChannelCmd?=?ENABLE; ??//?初始化配置NVIC ??NVIC_Init(&NVIC_InitStructure); }
//并在DEBUG_USART_Config函数第三步前面添加 //串口中断优先级配置 NVIC_Configuration(); //使能串口接收中断 USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);
main.c:
#include?"stm32f10x.h" #include?"./uart/bsp_usart.h"
//?接收缓冲,最大100个字节 uint8_t?USART_RX_BUF[100]; //?接收状态标记位 uint16_t?USART_RX_FLAG=0;
//串口中断服务函数 void?DEBUG_USART_IRQHandler(void) { uint8_t?temp; //接收中断 if(USART_GetFlagStatus(DEBUG_USARTx,?USART_IT_RXNE)?!=?RESET) { //?读取接收的数据 temp?=?USART_ReceiveData(DEBUG_USARTx); //接收未完成 if((USART_RX_FLAG?&?0x8000)==0) { //接收到了0x0d if(USART_RX_FLAG?&?0x4000) { //?接收错误,重新开始 if(temp?!=?0x0a)?USART_RX_FLAG=0; //?接收完成 else?USART_RX_FLAG?|=?0x8000; } //?还未接收到0x0d else { if(temp?==?0x0d) { USART_RX_FLAG?|=?0x4000; } else { USART_RX_BUF[USART_RX_FLAG?&?0x3FFF]=temp; USART_RX_FLAG++; //接收数据错误,重新开始接收 if(USART_RX_FLAG?>?99)?USART_RX_FLAG=0; } } } } }
int?main(void) { uint8_t?len=0; uint8_t?i=0; //?USART初始化 USART_Config(); while(1) { if(USART_RX_FLAG?&?0x8000) { //?获取接收到的数据长度 len?=?USART_RX_FLAG?&?0x3FFF; USART_SendString(DEBUG_USARTx,?"发送消息:\n"); for(i=0;?i<len;i++) { //?向串口发送数据 USART_SendData(DEBUG_USARTx,?USART_RX_BUF[i]); //等待发送结束 while(USART_GetFlagStatus(DEBUG_USARTx,?USART_FLAG_TC)!=SET); } USART_SendString(DEBUG_USARTx,?"\n\n"); if(strcmp((char?*)USART_RX_BUF,"Stop,stm32!")==0) { USART_SendString(DEBUG_USARTx,?"stm32已停止发送!"); break; } USART_RX_FLAG=0; memset(USART_RX_BUF,0,sizeof(USART_RX_BUF)); } else { USART_SendString(DEBUG_USARTx,?"hello?windows!\n"); delay_ms(800); } } } 三.结果
烧录
?编译结果
?
?3.?STM32采用串口DMA方式,用115200bps或更高速率向上位机连续发送数据。
一.创建项目 打开USART1及DMA模式,在DMA?setting点击Add
?
?配置DMA参数
在Pinout&Configuration–Connectivity–USART1–NVIC?Settings中打开中断
二.编写代码
修改第二个实验中代码即可
在while循环中增加
HAL_UART_Transmit_DMA(&huart1,Senbuff,?sizeof(Senbuff)); ???HAL_Delay(1000);
三.结果
?
|