STM32は、水中クワッドローター(8)センシングタスク4バッテリーパワー検出を実現します

1.電圧検出の原理

電圧検出はロボットのバッテリー電力を検出することであり、リチウムバッテリーの電力は電圧値と正の相関があります。リチウム電池は過放電を固く禁じられています。そうしないと、特に水中ロボットの場合、損傷しやすくなります。電池が壊れた場合は、修理のためにキャビンを開けて再密閉する必要があり、非常にコストがかかります。

電圧検出の原理は非常に単純で、中学校で分圧定理を学びました。12Vまたは24Vのリチウム電池電圧を3.3V未満のADC検出範囲に下げるには、2つの抵抗を直列に接続するだけで済み、ADサンプリングを使用して電圧値を読み取ります。このプロジェクトでは、2つの抵抗を外部に接続し、STM32のADC関数で電圧を読み取ってから、バッテリー電圧を計算します。

2.ADC読み取り電圧ドライブコード

新しいadc.cおよびadc.hファイルを作成します

adc.hファイルの内容は次のとおりです。

#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ファイルの内容は次のとおりです。

#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パラメーターが平均を設定する回数であるということです。

3.センシングタスクの読み取り電圧アプリケーションコードを増やします

以前に作成したsensor.cファイルとsensor.hファイルに戻り、以前に姿勢と水深を読み取るためのコードを追加しましたが、現在は電圧を読み取るためのコードを増やし続けています。

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)。この関数は実際にはセグメント化された平均です。ここでも移動平均フィルターを使用しています。読み取り速度が速くなり、エラーが小さくなります。

メインファイル検知タスクでは、電圧値を読み取るためのコードが追加されますが、実際には1行のコードのみが追加されます。sensorReadVoltage(&sensorData.voltage)

sensor_taskの内容は次のようになります(前の内容と比較して読むことをお勧めします)。

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+, 所以这里的延时小一点
	}
}

おすすめ

転載: blog.csdn.net/qq_30267617/article/details/114579271