IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 中断及串口通信进阶 -> 正文阅读

[嵌入式]中断及串口通信进阶

学习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中配置为如下模式

4b667b5bb95147cdb694f5d335c280eb.jpeg

?配置中断优先级:在Pinout&Configuration–System?core–NVIC中使能外部中断,并配置优先级

d3459db266834ee1aeba9f248ce6446f.jpeg

?配置时钟:设时钟频率为72MHZ

生成项目

3665a045bebd46cb96fd61b59a6861ed.jpeg

?二.

代码:

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文件中加入中断服务函数

b9729a13d30641b8bda540434eda1c17.jpeg

?每次按键按下,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;
??}
}

三.结果

烧录

9c211eb8e99d4951afd86e7231c65c23.jpeg

2d216e27829947108622d9fbaa9946cc.jpeg??

每一次接地,中断一次

ad0bcd537fc34e6ebebd45ae7a17fbfa.jpeg

be5f184a38ee43d28e25dd3773db6c06.jpeg

296feaa20a3b4945807f03b8787a660e.jpeg

?2.?采用串口中断方式重做上周的串口通信作业,分别实现:1)当stm32接收到字符“s”时,停止持续发送“hello?windows!”;?当接收到字符“t”时,持续发送“hello?windows!”(提示:采用一个全局标量做信号灯);2)当stm32接收到字符“stop?stm32!”时,停止持续发送“hello?windows!”;?当接收到字符“go?stm32!”时,持续发送“hello?windows!”(提示:要将接收到的连续字符保存到一个字符数组里,进行判别匹配。写一个接收字符串的函数。

一.创建项目

设置串口USART1,在MODE下选择Asynchronous,在如下界面下选择中断

98373fec7dbd4c90924b31e0e36d0482.jpeg

?二.?编写函数

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);

三.结果

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 12:14:20  更:2022-10-31 12:18:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:37:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码