首页
关于本站
其他站点
意见反馈
更多
我的目标
假期规划
Search
1
分享一下我觉得还不错的摘抄句子
251 阅读
2
过年啦
237 阅读
3
看职高三年,又是三年,好快!
153 阅读
4
聊那天给学校做个全景地图,现在想起也挺尴尬的
147 阅读
5
这两个有趣的md5
116 阅读
日常生活
随手一记
学习踩坑
技术分享
学习笔记
STM32
登录
Search
你的糖来啦
累计撰写
35
篇文章
累计收到
6
条评论
首页
栏目
日常生活
随手一记
学习踩坑
技术分享
学习笔记
STM32
页面
关于本站
其他站点
意见反馈
我的目标
假期规划
搜索到
8
篇与
的结果
2024-06-25
STM32输入捕获测频率&PWMI测频率占空比
本文待补充,暂只有流程代码输入捕获#include "stm32f10x.h" // Device header void IC_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_InternalClockConfig(TIM3); TIM_TimeBaseInitTypeDef TIM_TimBaseInitStructure; TIM_TimBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimBaseInitStructure.TIM_Period = 65536 -1; TIM_TimBaseInitStructure.TIM_Prescaler = 72 -1; TIM_TimBaseInitStructure.TIM_RepetitionCounter =0; TIM_TimeBaseInit(TIM3, &TIM_TimBaseInitStructure); /*配置输入捕获*/ TIM_ICInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_Channel = TIM_Channel_1; //配置通道 TIM_InitStructure.TIM_ICFilter = 0xF ; //配置滤波 TIM_InitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性 配置上升沿触发 TIM_InitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //触发信号分频器 1分频就是不分配 每次触发都有效果 TIM_InitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉 TIM_ICInit(TIM3, &TIM_InitStructure); /*配置主从模式*/ TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1); //配置触发源 TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //配置从模式 TIM_Cmd(TIM3,ENABLE); } /*获取频率*/ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); //可删除1不影响代码 } PWMI#include "stm32f10x.h" // Device header void IC_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_InternalClockConfig(TIM3); TIM_TimeBaseInitTypeDef TIM_TimBaseInitStructure; TIM_TimBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimBaseInitStructure.TIM_Period = 65536 -1; TIM_TimBaseInitStructure.TIM_Prescaler = 72 -1; TIM_TimBaseInitStructure.TIM_RepetitionCounter =0; TIM_TimeBaseInit(TIM3, &TIM_TimBaseInitStructure); /*配置输入捕获*/ TIM_ICInitTypeDef TIM_InitStructure; TIM_InitStructure.TIM_Channel = TIM_Channel_1; //配置通道 TIM_InitStructure.TIM_ICFilter = 0xF ; //配置滤波 TIM_InitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //极性 配置上升沿触发 TIM_InitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //触发信号分频器 1分频就是不分配 每次触发都有效果 TIM_InitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //输入信号交叉,选择直通,不交叉 TIM_ICInit(TIM3, &TIM_InitStructure); /*简化步骤,配置一条与上面代码不同通道的TIM_Channel和TIM_ICPolarity 实现交叉模式*/ TIM_PWMIConfig(TIM3, &TIM_InitStructure); /*配置主从模式*/ TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1); //配置触发源 TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset); //配置从模式 TIM_Cmd(TIM3,ENABLE); } /*获取频率*/ uint32_t IC_GetFreq(void) { return 1000000 / (TIM_GetCapture1(TIM3) + 1); } /*获取占空比*/ uint16_t IC_GetDuty(void) { return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1); }
2024年06月25日
10 阅读
0 评论
0 点赞
2024-06-23
STM32使用PWM驱动舵机
舵机的工作原理以9g舵机为例有三根线:电源正极 电源负极 信号线(输入PWM)我么可以通过PWM来控制舵机转动,其中改变PWM的占空比可以控制舵机角度,如下图所示:使用PWM控制舵机的要求以9g舵机为例,要求控制PWM为50Hz 周期为20ms代码部分PWM.c#include "stm32f10x.h" // Device header void PWM_Init(void) { //启动TIM GPIO RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; //需要使用GPIO来输出PWM PWM来自片上外设TIM 所以设置为复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //配置TIM //CK_PSC时钟频率 PSC分频 ARR自动重装 //PWM频率 = CK_PSC/(PSC+1)/(ARR+1) //PWM占空比 = CCR/(ARR+1) //PWM分辨率 = 1/(ARR+1) TIM_InternalClockConfig(TIM2); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1; //ARR TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1; //CK_PSC TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; //初始化赋值 为了代码维护性 TIM_OCStructInit(&TIM_OCInitStructure); //选择输出模式 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 = 0; //CCR TIM_OC2Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2,ENABLE); } //更改CCR占空比用的 void PWM_SetCompare2(uint16_t Compare) { TIM_SetCompare2(TIM2,Compare); } 控制舵机角度 servo.c#include "stm32f10x.h" // Device header #include "PWM.h" void Servo_Init() { PWM_Init(); } void Servo_SetAngle(float Angle) { PWM_SetCompare2(Angle / 180 *2000 + 500); } 按钮部分 Key.c#include "stm32f10x.h" // Device header #include "Delay.h" /** * 函 数:按键初始化 * 参 数:无 * 返 回 值:无 */ void Key_Init(void) { /*开启时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟 /*GPIO初始化*/ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB1和PB11引脚初始化为上拉输入 } /** * 函 数:按键获取键码 * 参 数:无 * 返 回 值:按下按键的键码值,范围:0~2,返回0代表没有按键按下 * 注意事项:此函数是阻塞式操作,当按键按住不放时,函数会卡住,直到按键松手 */ uint8_t Key_GetNum(void) { uint8_t KeyNum = 0; //定义变量,默认键码值为0 if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //读PB1输入寄存器的状态,如果为0,则代表按键1按下 { Delay_ms(20); //延时消抖 while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //等待按键松手 Delay_ms(20); //延时消抖 KeyNum = 1; //置键码为1 } if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0) //读PB11输入寄存器的状态,如果为0,则代表按键2按下 { Delay_ms(20); //延时消抖 while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0); //等待按键松手 Delay_ms(20); //延时消抖 KeyNum = 2; //置键码为2 } return KeyNum; //返回键码值,如果没有按键按下,所有if都不成立,则键码为默认值0 } main.c#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Key.h" #include "servo.h" uint8_t Key_Num; float Angle; int main(void) { /*模块初始化*/ OLED_Init(); //OLED初始化 Key_Init(); Servo_Init(); OLED_ShowString(1,1,"Angle:"); while (1){ Key_Num = Key_GetNum(); if(Key_Num == 1) { Angle += 30; if(Angle > 180) { Angle = 0; } } Servo_SetAngle(Angle); OLED_ShowNum(1, 7, Angle, 3); } }
2024年06月23日
27 阅读
0 评论
0 点赞
2024-06-23
STM32使用PWM驱动LED呼吸灯
使用PWM来实现LED呼吸灯的效果步骤开启并配置TIM和GPIO时钟GPIO需要设置成为复用推挽输出根据实际需要配置合适的时基单元(PWM频率)配置好输入比较寄存器具体如下注意:本代码是使用比较通道1,对用在PA0上输出PWM主要代码 PWM.c#include "stm32f10x.h" // Device header void PWM_Init(void) { //启动TIM GPIO RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; //需要使用GPIO来输出PWM PWM来自片上外设TIM 所以设置为复用推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //配置TIM //CK_PSC时钟频率 PSC分频 ARR自动重装 //PWM频率 = CK_PSC/(PSC+1)/(ARR+1) //PWM占空比 = CCR/(ARR+1) //PWM分辨率 = 1/(ARR+1) TIM_InternalClockConfig(TIM2); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //CK_PSC TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //ARR TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure); TIM_OCInitTypeDef TIM_OCInitStructure; //初始化赋值 为了代码维护性 TIM_OCStructInit(&TIM_OCInitStructure); //选择输出模式 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 = 0; //CCR TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_Cmd(TIM2,ENABLE); } //更改CCR占空比用的 void PWM_SetCompare1(uint16_t Compare) { TIM_SetCompare1(TIM2,Compare); } main.c#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "PWM.h" int main(void) { /*模块初始化*/ OLED_Init(); //OLED初始化 PWM_Init(); OLED_ShowString(1,1,"Pulse:"); while (1) { for(uint16_t i = 0;i <= 100; i++) { PWM_SetCompare1(i); OLED_ShowNum(2,1,i,3); //屏幕上显示占空比 可删除 Delay_ms(20); } for(uint16_t i = 0;i <= 100; i++) { PWM_SetCompare1(100 - i); OLED_ShowNum(2,1,100 - i,3); Delay_ms(20); } } }
2024年06月23日
15 阅读
0 评论
0 点赞
2024-06-21
STM32定时器定时中断
图片来源bilibil 江协科技 上图为定时器中断结构,我们使用定时器中断的操作步骤:选择时钟源(如上图左内部时钟、外部时钟、其他定时器、通道捕获)初始化时基单元配置中断输出控制配置NVIC使能时钟运行控制以下为一个示例 1s触发一次中断#include "stm32f10x.h" // Device header void Timer_Init(void) { //启动APB1下的TIM2通用定时器 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //选择TIM2通用定时器 系统默认配置使用 可以不配置 但是规范流程 写一下 TIM_InternalClockConfig(TIM2); //初始化时基单元 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitSturcture; //选择时钟分频 这里是1分频就是不分频 TIM_TimeBaseInitSturcture.TIM_ClockDivision = TIM_CKD_DIV1; //选择计数模式 向上计数 TIM_TimeBaseInitSturcture.TIM_CounterMode = TIM_CounterMode_Up; //因为从0开始所以需要减一 //stm32103c8单片机频率是72Mhz; 72M分频(除以)7200 = 10000 的意思是单片机进行7200分频得到每秒10000个震动 ,然后计数设置成10000每10000次触发一次更新 TIM_TimeBaseInitSturcture.TIM_Period = 10000 -1; TIM_TimeBaseInitSturcture.TIM_Prescaler = 7200 -1; //高级定时器才有 这里填0 TIM_TimeBaseInitSturcture.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitSturcture); //手动清除一次标志位 系统初始化时手动触发了更新事件 因此手动清除一次标志位 可以理解不清除的话代码单片机上电就会从1开始 但是计数是从0开始 TIM_ClearFlag(TIM2,TIM_FLAG_Update); //中断输出控制 允许TIM2定时器更新 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //NVIC NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); //使能TIM2 TIM_Cmd(TIM2,ENABLE); } //配置TIM2的中断函数 这个格式固定可以开始文件中找到 void TIM2_IRQHandler(void) { //检查中断标志位 规范步骤 if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET) { //需要中断执行的代码块 //代码结束清除标志位 不然退出不了中断函数 TIM_ClearITPendingBit(TIM2,TIM_IT_Update); } }
2024年06月21日
10 阅读
0 评论
0 点赞
2024-06-19
STM32按钮控制LED
{callout color="#f0ad4e"}前言{/callout} 本文使用的是非是轮询方式。 使用按钮来来控制LED的点亮和熄灭效果,按钮对应的GPIO需要设置为输入模式,本文配置GPIOB的PB1和PB11用作读取按钮使用上拉输入。配置GPIOA的PA1和PA2为位LED的输出脚,LED使用低电平驱动方式首先我们在主函数中不断获取按钮状态来判断是否更新LED的状态#include "stm32f10x.h" // Device header #include "Delay.h" #include "LED.h" #include "Key.h" uint8_t key_num; int main(void) { LED_Init(); Key_Init(); while(1) { //获取按钮返回值 key_num = Key_GetNum(); if(key_num == 1) { LED1_Turn(); } if(key_num == 2) { LED2_Turn(); } } } LED的驱动文件#include "stm32f10x.h" // Device header //初始化LED使用的GPIO void LED_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef InitStructure; InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; InitStructure.GPIO_Speed= GPIO_Speed_50MHz; GPIO_Init(GPIOA, &InitStructure); GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2); } //设置LED的状态 //开 void ON_LED_1(void) { GPIO_ResetBits(GPIOA,GPIO_Pin_1); } void ON_LED_2(void) { GPIO_ResetBits(GPIOA,GPIO_Pin_2); } //关 void OFF_LED_1(void) { GPIO_SetBits(GPIOA,GPIO_Pin_1); } void OFF_LED_2(void) { GPIO_SetBits(GPIOA,GPIO_Pin_2); } //当前状态取反 如果为打开就关闭 如果关闭就打开 void LED1_Turn(void) { //获取当前GPIO状态 并判断 if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1) == 0) { GPIO_SetBits(GPIOA,GPIO_Pin_1); } else { GPIO_ResetBits(GPIOA,GPIO_Pin_1); } } void LED2_Turn(void) { //获取当前GPIO状态 并判断 if(GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2) == 0) { GPIO_SetBits(GPIOA,GPIO_Pin_2); } else { GPIO_ResetBits(GPIOA,GPIO_Pin_2); } } 按钮的驱动文件#include "stm32f10x.h" // Device header #include "Delay.h" void Key_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStructuer; //输入是设置GPIO为上拉输入 GPIO_InitStructuer.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructuer.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11; //输入时这个参数无效 //GPIO_InitStructuer.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructuer); } uint8_t Key_GetNum(void) { uint8_t keyNum = 0; //按钮1 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0) { //消除按钮按下的抖动 Delay_ms(20); while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0); //消除按钮松开的抖动 Delay_ms(20); keyNum = 1; } //按钮2 if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0) { //消除按钮按下的抖动 Delay_ms(20); while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11) == 0); //消除按钮松开的抖动 Delay_ms(20); keyNum = 2; } return keyNum; }
2024年06月19日
12 阅读
0 评论
0 点赞
1
2