基于STM32F1的自动追光云台(代码开源)

2024-02-19 12:30

本文主要是介绍基于STM32F1的自动追光云台(代码开源),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前一段时间做了一个自动追光云台(大家感兴趣的也可以自己DIY一个呀),用来自动捕捉阳光供太阳板发电提高太阳板的发电效率,我用了一款STM32f103c8t6为主控来控制云台舵机的旋转。感光元器件使用的是光敏传感器(淘宝随便买一款啊很便宜)来感知光强,所以用ADC进行模拟量采集光强信息。下面就来介绍介绍它吧!

  1. 舵机旋转的控制

舵机的主要组成部分为伺服电机,伺服就是服从信号的要求从而做出相应动作。在信号发出之前,电机停止不动;信号发出之后,电机立即做旋转运动。因此我们就可以给舵机输入不同的信号,来控制其旋转到不同的角度。舵机接收的是PWM信号,当信号进入内部电路产生一个偏置电压,触发电机通过减速齿轮带动电位器移动,使电压差为零时,电机停转,从而达到伺服的效果。简单来说就是给舵机一个特定的PWM信号,舵机就可以旋转到指定的位置。

舵机上有三根线,分别是GND、VCC和SIG,也就是地线、电源线和信号线,其中的PWM波就是从信号线输入给舵机的。一般来说,舵机接收的PWM信号频率为50HZ,即周期为20ms。当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。

舵机是通过高电平的占空比来调节输出轴的角度,舵机的驱动信号是50Hz的方波信号,每个周期为20ms,其中高电平的占比在0.5ms-2.5ms之间。

在这Keil里编写PWM程序,通过使用TIM_SetComparex(TIMx, Compare)函数来改变PWM的输出占空比。ok下面就是PWM初始化程序

void PWM2_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  //开启定时器2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //设置PA1引脚为复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_InternalClockConfig(TIM2);  //定时器2内部时钟配置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;   //PSC时钟预分频,这里我们使用的是f103的72MHz所以除以72进行分频得到1MHz的的时钟频率TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;             //输出为PWM模式2的向下计数模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      //设置问低电平有效TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //输出通道使能TIM_OCInitStructure.TIM_Pulse = 0;                            //CCR这里设置为0,下面使用函数对其在运行时改变他的他的它大小TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);   //开启定时器2 
}void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare);   //设置PWM占空比还能输函数,通过改变Compare的值来PWM占空比,其范围为0~ARR
}/*定时器3的初始化和定时器2是一样的了*/
void PWM3_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);TIM_InternalClockConfig(TIM3);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;        //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;        //PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;        //CCRTIM_OC4Init(TIM3, &TIM_OCInitStructure);//    TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);
//    TIM_ARRPreloadConfig(TIM3,ENABLE);TIM_Cmd(TIM3, ENABLE);
}void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare4(TIM3, Compare);
}

2.光敏传感器的模拟量采集

光敏传感器在上电后受到不同强度的光照射后会通过传感器上信号线反馈出一个连续的模拟信号,但是单片机在处理信息的时候都是数字量的,所以我们需要把模拟量转化为数字量。stm32f103上有自带的ADC采样的功能,分为8位和12位的不同方式,在这里我使用了12位ADC的模式。在这个追光云台上有4个光敏传感器模块,要对4个模拟量都进行采集,所以使用ADC的扫描模式,并且涉及到多通道数据采集为了不给CPU产生负担,准备使用DMA数据转运的方式进行数据的储存。

1.ADC简单介绍

ADC电路就是指模数转换电路。也就是将模拟信号变为数字信号。一般用在数据采集方面。ADC,Analog-to-Digital Converter的缩写,指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让 ADC 的时钟超过 14M,否则将导致结果准确度下降。STM32 将 ADC 的转换分为 2 个通道组:规则通道组注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。

2.DMA简单介绍

DMA,全称为:Direct Memory Access,即直接存储器访问。DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。

(这个图是参考江科大自动化协的)

好了直接上代码吧!

/*AD*/
uint16_t AD_Value[4]; //AD数据存放的位置
void AD_Init(void)   
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);    //开启DMA1的时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);  //ADC挂载的时钟6分频GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);   //规则组通道的配置ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_55Cycles5);ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //数据右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_NbrOfChannel = 4;ADC_Init(ADC1, &ADC_InitStructure);DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  //数据搬运的地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;       //数据将要搬到的地址DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_BufferSize = 4;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;DMA_Init(DMA1_Channel1, &DMA_InitStructure);DMA_Cmd(DMA1_Channel1, ENABLE);ADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE);ADC_ResetCalibration(ADC1);while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

3.云台自动追光的实现方法

在图中可以看到,四个光敏传感器安装在四个角上,因为它们感受到的光强都是不同的,这里我处理的方法是avt=左上和右上之和除2、avb=左下和右下之和除2、avl=左上和左下之和除2、avr=右上和右下之和除2,这样就得到了avt,avb,abl,avr这4个值。在对这4个值进行对比判断时有一个特别重要的量不得不说,那就是tol它就是决定着我们这个云台对光强的灵敏度了,它就相当于一个阈值把要判断的结果卡在这个范围内,只有在这个范围内,才能进行接下来的上面得到的4个值的比较。

  1. 上下差值dvert=avt-avb 上-下 ,左右差值dhoriz=avl-avr 左-右;

  1. 如果上下差值dvert在tol(这就体现了上面说到的灵敏度这个概念了,tol越小就说明上下差值很容易满足在tol范围外)之外就可以比较avt和avb的大小了,每次判断增加或减速上下旋转舵机的占空比大小了最终使得上下差值进入tol范围内,舵机不在旋转达到我们的目标;

  1. 那么判断左右就和上下一样的方法啦。

这里就是主函数程序了

Servo1_SetAngle(50);             //控制上下旋转,PA1
Servo2_SetAngle(100);       //控制左右旋转,PB1
uint8_t tol=2;               //照度的相应范围,越小越灵敏while (1){zs = (float)AD_Value[0]/ 4095 * 100;   //PA4zx = (float)AD_Value[1]/ 4095 * 100;   //PA5ys = (float)AD_Value[2]/ 4095 * 100;   //PA6yx = (float)AD_Value[3]/ 4095 * 100;   //PA7avt=(zs+ys)/2;   //上avb=(zx+yx)/2;   //下avl=(zs+zx)/2;   //左avr=(ys+yx)/2;   //右dvert=avt-avb;   //上-下dhoriz=avl-avr;  //左-右if (-1*tol > dvert || dvert > tol) {if (avt > avb){servov++;if (servov > servovLimitHigh) { servov = servovLimitHigh;}}else if (avt < avb){servov--;if (servov < servovLimitHigh){servov = servovLimitLow;}}Servo1_SetAngle(50+servov);     //PA1}//检查差异是否在公差范围内,否则改变水平角度  if (-1*tol > dhoriz || dhoriz > tol) {if (avl > avr)         //左>右{servoh++; if (servoh > servohLimitHigh){servoh = servohLimitHigh;}}else if (avl < avr)    //右<左{servoh--;if (servoh < servohLimitLow){servoh = servohLimitLow;}}Servo2_SetAngle(100+servoh);     //PB1}Delay_ms(1);}
}

原工程代码:

链接:https://pan.baidu.com/s/1ZhUwJNlQqWLXtNjR9RtSdw

提取码:m5w6

创作不易在这里如有不对的地方还请大家可以指出!!

这篇关于基于STM32F1的自动追光云台(代码开源)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/724655

相关文章

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

Java中Map.Entry()含义及方法使用代码

《Java中Map.Entry()含义及方法使用代码》:本文主要介绍Java中Map.Entry()含义及方法使用的相关资料,Map.Entry是Java中Map的静态内部接口,用于表示键值对,其... 目录前言 Map.Entry作用核心方法常见使用场景1. 遍历 Map 的所有键值对2. 直接修改 Ma

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

深入解析 Java Future 类及代码示例

《深入解析JavaFuture类及代码示例》JavaFuture是java.util.concurrent包中用于表示异步计算结果的核心接口,下面给大家介绍JavaFuture类及实例代码,感兴... 目录一、Future 类概述二、核心工作机制代码示例执行流程2. 状态机模型3. 核心方法解析行为总结:三

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061

pandas实现数据concat拼接的示例代码

《pandas实现数据concat拼接的示例代码》pandas.concat用于合并DataFrame或Series,本文主要介绍了pandas实现数据concat拼接的示例代码,具有一定的参考价值,... 目录语法示例:使用pandas.concat合并数据默认的concat:参数axis=0,join=

C#代码实现解析WTGPS和BD数据

《C#代码实现解析WTGPS和BD数据》在现代的导航与定位应用中,准确解析GPS和北斗(BD)等卫星定位数据至关重要,本文将使用C#语言实现解析WTGPS和BD数据,需要的可以了解下... 目录一、代码结构概览1. 核心解析方法2. 位置信息解析3. 经纬度转换方法4. 日期和时间戳解析5. 辅助方法二、L

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示