我是靠谱客的博主 天真流沙,这篇文章主要介绍STM32实现水下四旋翼(八)传感任务4——电池电量检测一. 电压检测原理二. ADC读电压驱动代码三. 传感任务增加读电压应用代码,现在分享给大家,希望可以做个参考。

目录

  • 一. 电压检测原理
  • 二. ADC读电压驱动代码
  • 三. 传感任务增加读电压应用代码

一. 电压检测原理

电压检测是为了检测机器人的电池电量,锂电池的电量与电压值是呈正相关的。锂电池是严禁过放的,不然很容易损坏,尤其是对于水下机器人,电池坏了就要开舱维修,重新密封,代价很大。

电压检测原理很简单,初中都学过的分压定理。只需要两个电阻串联,将12V或24V的锂电电压降到3.3V以下的ADC检测范围,然后使用AD采样就可以读出电压值了。本项目中其实就是外连了两个电阻,然后用STM32的ADC功能读取电压,再推算电池电压。

二. ADC读电压驱动代码

新建一个adc.c和adc.h文件

adc.h文件内容如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
#ifndef __ADC_H #define __ADC_H #include "sys.h" #define MAX_VOLTAGE 25.2f/11.0f void MY_ADC_Init(void); //ADC通道初始化 u16 Get_Adc(u32 ch); //获得某个通道值 u16 Get_Adc_Average(u32 ch,u8 times);//得到某个通道给定次数采样的平均值 #endif

因为使用的6S电池,满电25.2V,分压为1/11,所以最大电压25.2/11.

adc.c文件内容如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "adc.h" #include "delay.h" ADC_HandleTypeDef ADC1_Handler;//ADC句柄 //初始化ADC //ch: ADC_channels //通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16 void MY_ADC_Init(void) { ADC1_Handler.Instance=ADC1; ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B; //12位模式 ADC1_Handler.Init.DataAlign=ADC_DATAALIGN_RIGHT; //右对齐 ADC1_Handler.Init.ScanConvMode=DISABLE; //非扫描模式 ADC1_Handler.Init.EOCSelection=DISABLE; //关闭EOC中断 ADC1_Handler.Init.ContinuousConvMode=DISABLE; //关闭连续转换 ADC1_Handler.Init.NbrOfConversion=1; //1个转换在规则序列中 也就是只转换规则序列1 ADC1_Handler.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式 ADC1_Handler.Init.NbrOfDiscConversion=0; //不连续采样通道数为0 ADC1_Handler.Init.ExternalTrigConv=ADC_SOFTWARE_START; //软件触发 ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发 ADC1_Handler.Init.DMAContinuousRequests=DISABLE; //关闭DMA请求 HAL_ADC_Init(&ADC1_Handler); //初始化 } //ADC底层驱动,引脚配置,时钟使能 //此函数会被HAL_ADC_Init()调用 //hadc:ADC句柄 void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟 GPIO_Initure.Pin=GPIO_PIN_4; //PA5 GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟 GPIO_Initure.Pull=GPIO_NOPULL; //不带上下拉 HAL_GPIO_Init(GPIOA,&GPIO_Initure); } //获得ADC值 //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16 //返回值:转换结果 u16 Get_Adc(u32 ch) { ADC_ChannelConfTypeDef ADC1_ChanConf; ADC1_ChanConf.Channel=ch; //通道 ADC1_ChanConf.Rank=1; //1个序列 ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间 ADC1_ChanConf.Offset=0; HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置 HAL_ADC_Start(&ADC1_Handler); //开启ADC HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换 return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果 } //获取指定通道的转换值,取times次,然后平均 //times:获取次数 //返回值:通道ch的times次转换结果平均值 u16 Get_Adc_Average(u32 ch,u8 times) { u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+=Get_Adc(ch); delay_ms(5); } return temp_val/times; }

这里面的调用函数就是u16 Get_Adc_Average(u32 ch,u8 times),times参数是设置平均的次数。

三. 传感任务增加读电压应用代码

回到之前我们创建的sensor.c和sensor.h文件,之前我们在里面增加了读姿态和水深的代码,现在我们继续增加读电压的代码。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
float filterVolt[10]; float sumVolt; u8 count_volt; void sensorReadVoltage(float *volt) { u16 adc_value; float adc_result; float temp; adc_value = Get_Adc(ADC_CHANNEL_4); adc_result = (float)adc_value * (3.3/4096); temp = filterVolt[count_volt]; filterVolt[count_volt] = adc_result; sumVolt += filterVolt[count_volt] - temp; count_volt++; if (count_volt == 10) count_volt = 0; *volt = sumVolt / 10.0f * 7.635; // 分压1/11 }

这个地方没有使用前面adc.c文件中的u16 Get_Adc_Average(u32 ch,u8 times),这个函数其实是分段平均。我这里依然使用的滑动平均滤波,读取速度会更快,误差也更小。

main文件传感任务中增加读电压值的代码,其实只增加了一行代码,sensorReadVoltage(&sensorData.voltage)

sensor_task内容变成这样(建议与上一篇对照阅读):

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
u8 sensor_task(void *p_arg) { OS_ERR err; CPU_SR_ALLOC(); float Gyro[3], Angle[3]; float wDepth; u8 count = 20; //滤波初始化 while (count--) { sensorReadAngle(Gyro, Angle); sensorReadDepth(&wDepth); } // 初始化之后,所有期望值复制为实际值 state.realAngle.roll = Angle[0]; state.realAngle.pitch = Angle[1]; state.realAngle.yaw = Angle[2]; state.realDepth = wDepth; setstate.expectedAngle.roll = state.realAngle.roll; setstate.expectedAngle.pitch = state.realAngle.pitch; setstate.expectedAngle.yaw = state.realAngle.yaw; //初始化之后将当前的姿态角作为期望姿态角初值 setstate.expectedDepth = state.realDepth; while (1) { /********************************************** 获取期望值与测量值*******************************************/ sensorReadAngle(Gyro, Angle); sensorReadDepth(&wDepth); //反馈值 state.realAngle.roll = Angle[0]; state.realAngle.pitch = Angle[1]; state.realAngle.yaw = Angle[2]; tate.realDepth = wDepth; state.realRate.roll = Gyro[0]; state.realRate.pitch = Gyro[1]; state.realRate.yaw = Gyro[2]; sensorReadVoltage(&sensorData.voltage); delay_ms(5); // 水深传感器单次读取需要20ms+, 所以这里的延时小一点 } }

最后

以上就是天真流沙最近收集整理的关于STM32实现水下四旋翼(八)传感任务4——电池电量检测一. 电压检测原理二. ADC读电压驱动代码三. 传感任务增加读电压应用代码的全部内容,更多相关STM32实现水下四旋翼(八)传感任务4——电池电量检测一.内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(66)

评论列表共有 0 条评论

立即
投稿
返回
顶部