完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
总体思路
通过串口输入数据到单片机,单片机判断串口数据中的关键字,然后判定是哪一种模式(或者根据中断按键输入改变的模式) 再去对应的模式实现相应的功能 整个程序分为两个部分,程序的轮询和中断两部分 中断部分包括 定时器中断,串口中断,外部中断 定时器中断:LED2利用定时器进行延时,中断中执行相应的LED2的操作 串口中断:接收PC向单片机发送的数据。 外部中断:判断按键状态,改变MODE的值 轮询部分 数据识别:对串口中断中的数据识别,判定模式 数据输出:将可选MODE输出到串口,方便用户在PC机上查看 MODE输出:根据串口数据识别到的MODE或外部中断识别到的MODE进行相关模式的操作。 部分函数说明 void USART1_IRQHandler(void); 串口中断函数,里面定义了一个协议,所发送的字符串必须以回车键结束,很重要!!! 这个函数的数据接收过程参考https://blog.csdn.net/weixin_47586883/article/details/110959012 void usart_check(void); 这个函数的作用是对串口的数据进行识别,判定MODE void usart_out(void); 这个函数的作用是将用户选择的MODE输出到串口 void led_out(void);这个函数的作用是根据用户选择的MODE进行相应的操作,主要是LED1,LED2的操作在相应的TIM3中断中 void TIM3_IRQHandler(void);TIM3中断函数,也包含了对相应的MODE对LED2的操作 void EXTI2_IRQHandler(void);根据外部按键,记录MODE LED1连接A0采用systick控制时间,LED2连接A1,采用TIM3控制 外部中断按键连接A2,A2采取上拉输入,外部中断下降沿触发 A0,A1,均使用PWM输出 文件结构 主函数 #include“configuration.h” int main(void) { GPIO_Configuration(); SysTick_Init(72); TIM3configuration(4999,7199);//定时时间500ms TIM2_CH1_CH2_PWM_Init(999,71);//1000HzPWM USART1_Init(9600);//波特率9600 NVIC_Configuration(); EXTI_Configuration(); while(1) { printf(“rn可供选择的模式有:rn”); printf(“rn MODE1:LED1亮,LED2秒闪rn”); printf(“rn MODE2:LED1,LED2交替秒闪rn”); printf(“rn MODE3:LED1,LED2同时秒闪rn”); printf(“rn MODE4:LED1秒闪,LED2亮rn”); printf(“rn MODE5:LED1,LED2为呼吸灯rn”); printf(“rn请输入选择的MODErn”); usart_check(); usart_out(); led_out(); } } #include“configuration.h” #ifndef __CONFIGURATION_H #define __CONFIGURATION_H #include “stm32f10x.h” #include “stdio.h” void GPIO_Configuration(void);//有关GPIO的配置和时钟配置 void NVIC_Configuration(void);//中断向量管理 void EXTI_Configuration(void);//外部中断 void USART1_Init(u32 bound);//串口初始化 void TIM3configuration(u16 per,u16 psc);//TIM3定时器初始化 void SysTick_Init(u8 SYSCLK); //systick定时器初始化 void delay_us(u32 nus);//延时微秒 void delay_ms(u16 nms);//延时毫秒 //数据接收的相关宏 #define USART_REC_LEN 200 //定义最大接收字节数 200 #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收 extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节。末字节为换行符 extern u16 USART_RX_STA; //接收状态标记寄存器 extern uint8_t MODE; //模式 extern uint8_t led2_value; //读取LED2的状态 void usart_check(void); void usart_out(void); void led_out(void); void TIM2_CH1_CH2_PWM_Init(u16 per,u16 psc); //TIM输出PWM到A0,A1 #endif gpio_configuration #include“configuration.h” void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//复用时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//TIM3时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//USART1时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//TIM2时钟 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_0; //Led引脚A1,A0 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //外部中断A2 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */ } EXTI中断 #include“configuration.h” void EXTI_Configuration(void) { EXTI_InitTypeDef EXTI_InitStructure; GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource2);//配置中断线 EXTI_InitStructure.EXTI_Line=EXTI_Line2;//中断线PA0—PG0 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断方式 EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//下降沿触发 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); } void EXTI2_IRQHandler(void) { static uint8_t EXTflag=0; if(EXTI_GetITStatus(EXTI_Line2)!=RESET) { delay_ms(10); EXTI_ClearITPendingBit(EXTI_Line2); EXTflag++; switch(EXTflag) { case 1:MODE=1;break; case 2:MODE=2;break; case 3:MODE=3;break; case 4:MODE=4;break; case 5:MODE=5;break; } if(EXTflag==5)EXTflag=0; } } NVIC_Configuration配置 #include“configuration.h” void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStruct; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//管理分组 NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; NVIC_InitStruct.NVIC_IRQChannelSubPriority=0; NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3 NVIC_InitStruct.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel = EXTI2_IRQn;//外部中断2通道 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3 NVIC_InitStruct.NVIC_IRQChannelSubPriority =3; //子优先级3 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStruct); } Systick #include“configuration.h” static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数 //初始化延迟函数 //SYSTICK的时钟固定为AHB时钟的1/8 //SYSCLK:系统时钟频率 void SysTick_Init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us=SYSCLK/8; fac_ms=(u16)fac_us*1000; } /******************************************************************************* * 函 数 名 : delay_us * 函数功能 : us延时, * 输 入 : nus:要延时的us数 注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21) * 输 出 : 无 *******************************************************************************/ void delay_us(u32 nus) { u32 temp; SysTick-》LOAD=nus*fac_us; //时间加载 SysTick-》VAL=0x00; //清空计数器 SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick-》CTRL; }while((temp&0x01)&&!(temp&(1《《16))); //等待时间到达 SysTick-》CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-》VAL =0X00; //清空计数器 } /******************************************************************************* * 函 数 名 : delay_ms * 函数功能 : ms延时, * 输 入 : nms:要延时的ms数 注意:nms的值,SysTick-》LOAD为24位寄存器, 不要大于0xffffff*8*1000/SYSCLK 对72M条件下,nms《=1864ms * 输 出 : 无 *******************************************************************************/ void delay_ms(u16 nms) { u32 temp; SysTick-》LOAD=(u32)nms*fac_ms; //时间加载(SysTick-》LOAD为24bit) SysTick-》VAL =0x00; //清空计数器 SysTick-》CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do { temp=SysTick-》CTRL; }while((temp&0x01)&&!(temp&(1《《16))); //等待时间到达 SysTick-》CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器 SysTick-》VAL =0X00; //清空计数器 } TIM3_init #include “configuration.h” void TIM3configuration(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Period=per; //定时周期 TIM_TimeBaseInitStruct.TIM_Prescaler=psc; //分频系数 TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分频 TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//计数模式 TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//打开更新中断 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); TIM_Cmd(TIM3,ENABLE); } void TIM3_IRQHandler(void) { static uint8_t TIMflag=0; if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)//判断标志位状态 { TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清楚中断标志位 TIMflag++; switch(MODE) { case 1: if(TIMflag%2) { TIM_SetCompare2(TIM2,1000); } else { TIM_SetCompare2(TIM2,0); } break; case 2: if(TIMflag%2) { TIM_SetCompare2(TIM2,1000); led2_value=1; } else { TIM_SetCompare2(TIM2,0); led2_value=0; } break; case 3: if(TIMflag%2) { TIM_SetCompare2(TIM2,1000); led2_value=1; } else { TIM_SetCompare2(TIM2,0); led2_value=0; } break; } if(TIMflag==200)TIMflag=0; } } usart配置 #include“configuration.h” #if SYSTEM_SUPPORT_OS #include “includes.h” //ucos 使用 #endif //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART1-》SR&0X40)==0);//循环发送,直到发送完毕 USART1-》DR = (u8) ch; return ch; } #endif #if EN_USART1_RX //如果使能了接收 //串口1中断服务程序 //注意,读取USARTx-》SR能避免莫名其妙的错误 u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节。 //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART_RX_STA=0; //接收状态标记 void USART1_Init(u32 bound) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = bound;//波特率设置 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 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(USART1, &USART_InitStructure); //初始化串口1 USART_Cmd(USART1, ENABLE); //使能串口1 USART_ClearFlag(USART1, USART_FLAG_TC);//清除标志位 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断 } void USART1_IRQHandler(void) //串口1中断服务程序 { u8 Res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { Res =USART_ReceiveData(USART1); //读取接收到的数据 if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA》(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntExit(); #endif } #endif |
|
|
|
check
#include“configuration.h” uint8_t MODE; void usart_check(void) { u16 t; u16 len; if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度 printf(“rn您选择的模式是:rn”); for(t=0;t《len;t++) { USART_SendData(USART1, USART_RX_BUF[t]); //向串口1发送数据,将输入的MODE发送到串口窗口 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束 if(USART_RX_BUF[t]==0x31) //根据关键字判别模式 { MODE=1; } if(USART_RX_BUF[t]==0x32) { MODE=2; } if(USART_RX_BUF[t]==0x33) { MODE=3; } if(USART_RX_BUF[t]==0x34) { MODE=4; } if(USART_RX_BUF[t]==0x35) { MODE=5; } } USART_RX_STA=0; //置零串口接收状态寄存器 } } void usart_out(void) //根据识别到的模式,在串口显示 { switch(MODE) { case 1: printf(“rn当前模式MODE1rn”); break ; case 2: printf(“rn当前模式MODE2rn”); break ; case 3: printf(“rn当前模式MODE3rn”); break ; case 4: printf(“rn当前模式MODE4rn”); break ; case 5: printf(“rn当前模式MODE5rn”); break ; default:printf(“rn输入MODE错误,请从新输入MODErn”); } } LED_out #include“configuration.h” uint8_t led2_value; void led_out(void) { unsigned int i;//MODE5呼吸灯用 switch(MODE) { case 1: TIM_SetCompare1(TIM2,1000); //A0高电平 break; case 2: if(led2_value) { TIM_SetCompare1(TIM2,0); //A0低电平 } else { TIM_SetCompare1(TIM2,1000); } break; case 3: if(led2_value) { TIM_SetCompare1(TIM2,1000); } else { TIM_SetCompare1(TIM2,0); } break; case 4: TIM_SetCompare1(TIM2,0); TIM_SetCompare2(TIM2,1000);//A1高电平 delay_ms(500); TIM_SetCompare1(TIM2,1000); delay_ms(500); break; case 5: //呼吸灯 for(i=0;i《999;i++) { TIM_SetCompare2(TIM2,i); TIM_SetCompare1(TIM2,i); delay_ms(8); } for(i=999;i》0;i--) { TIM_SetCompare2(TIM2,i); TIM_SetCompare1(TIM2,i); delay_ms(8); } break; } } PWM配置 #include“configuration.h” void TIM2_CH1_CH2_PWM_Init(u16 per,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_TimeBaseInitStructure.TIM_Period=per; //自动装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式 TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure); //TIM2CH2通道 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //TIM_OCInitStructure.TIM_Pulse = 800;//需要固定PWM时使用,改变PWM使用TIM_SetCompare2(TIM2,i); TIM_OC2Init(TIM2,&TIM_OCInitStructure); //输出比较通道2初始化 TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable); //使能TIMx在 CCR2 上的预装载寄存器 //TIM2CH1通道 TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable; //TIM_OCInitStructure.TIM_Pulse = 800;//需要固定PWM时使用,改变PWM使用TIM_SetCompare1(TIM2,i); TIM_OC1Init(TIM2,&TIM_OCInitStructure); //输出比较通道2初始化 TIM_OC1PreloadConfig(TIM2,TIM_OCPreload_Enable); //使能TIMx在 CCR2 上的预装载寄存器 TIM_ARRPreloadConfig(TIM2,ENABLE);//使能预装载寄存器 TIM_Cmd(TIM2,ENABLE); //使能定时器 } 实验效果 模式1 模式2 模式3 模式4 模式5 实验问题,当控制两个灯同时闪烁时,会出现时序不同步的现象,推断是使用的库函数,程序运行相对较慢,不能保持和TIM定时器一致。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1771 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1619 浏览 1 评论
1070 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
724 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1673 浏览 2 评论
1936浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
729浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
569浏览 3评论
594浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
552浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 22:29 , Processed in 1.051135 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号