本文主要是介绍【STM32多路温控—第三章】ADC多通道采样,及数据上报,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
头文件定义
/* Define to prevent recursive inclusion ----------------------------------------------------------------*/
#ifndef __ADC1_TRANS_H__
#define __ADC1_TRANS_H__/*********************************************************************************************************/
/* 包含头文件 -------------------------------------------------------------------------------------------*/
#include "application.h"/* 宏定义 -----------------------------------------------------------------------------------------------*/\
#define ChannelNum 13
#define SampNum 10 //采样次数,使用平均滤波,采样10次取均值
#define ArrayNum 130 //缓存
#define B 3435 //B值,温度系数
#define TN 292.5 //额定温度(绝对温度加常温:273.15+25)
#define RN 10 //额定阻值(绝对温度下时的电阻值10K)
#define R2 100 //分压电阻100K
#define BaseVol 3.281 //ADC基准电压#define ad1 0
#define ad2 1
#define ad3 2
#define ad4 3
#define ad5 4
#define ad6 5
#define ad7 6
#define ad8 7
#define ad9 8
#define ad10 9
#define ad11 10
#define ad12 11
#define ad13 12
#define ad14 13extern int16_t *adctmpcontrol; // 定义数组指针变量
extern float *adctmparray;
/* 函数声明 ---------------------------------------------------------------------------------------------*/
void ADC1_Init(void);
void Adc_Handle(void);
uint16_t Get_Tempture_Value(uint16_t chx);
void Output_Tempture(void);
void Get_Bus_Current(void);/* 扩展变量 ---------------------------------------------------------------------------------------------*/#endif
c文件定义
定义一系列数组存放数据
static uint32_t AdcArrayLib[ArrayNum]={0}; // 13个ADC通道的10次采样缓存
static uint32_t Adc2dArray[SampNum][ChannelNum]; // AD转换结果缓存,10行6列
static uint16_t AdcFilterArray[ChannelNum]; // 滤波数组
static float AdcVoltArray[ChannelNum]; // 用于保存转换计算后的电压值
定义温度数组以及数组指针
static float AdcTmpArray[ChannelNum]; // 用于保存转换计算后的温度值
float *adctmparray = AdcTmpArray; // 定义数组指针变量static int16_t AdcTmpControl[ChannelNum];
int16_t *adctmpcontrol = AdcTmpControl; // 定义数组指针变量
封装ADC初始化
void ADC1_Init(void)
{MX_ADC1_Init();
// HAL_ADCEx_Calibration_Start(&hadc1);//ADC初始化后要进行校准,开启后不准确HAL_ADC_Start_DMA(&hadc1, AdcArrayLib, ArrayNum);
}
处理DMA采集的数据
void Adc_Handle(void)
{uint8_t i,j,n,m;int sum = 0;float RT;for(n = 0; n < SampNum; n++){for(m = 0; m < ChannelNum; m++){Adc2dArray[n][m] = AdcArrayLib[n*ChannelNum+m]; } } for(i = 0; i < ChannelNum; i++){for(j = 0; j < SampNum; j++){sum += Adc2dArray[j][i];}AdcFilterArray[i] = sum/SampNum;sum = 0;}for(i = 0; i < ChannelNum; i++){AdcVoltArray[i] = (double)(AdcFilterArray[i] & 0xFFF) * BaseVol / 4096; // NTC电压RT = AdcVoltArray[i] * 100 / (BaseVol-AdcVoltArray[i]); // 求出当前温度下的阻值,由串联分压得AdcTmpArray[i] = 1 / (1 / TN + (log(RT / RN) / B)) - 273.15; // RT=RN*exp*B(1/T-1/TN)-273.5AdcTmpControl[i]=ROUND_TO_INT16_1(AdcTmpArray[i]);}
}
输出温度值
我们利用上位机对MCU发送指令,意图就是根据发送的指令数值改变其中的参数值,或者执行相关函数。因此接收字节的处理这部分也是值得研究和学习的。
首先对数据结构进行确定。数据类型我们依然可以使用结构体进行定义。
typedef union {char Ch[2]; uint16_t Int;
}Format_UnionTypedef;typedef struct {__IO uint8_t Code; __IO Format_UnionTypedef data[13];//数据帧有13个参数
}MSG_TypeDef;
我们首先定义一个结构体,该结构体里面有两个数据类型,一个是具有13个参数的共同体数组,另一个是一个字节的参数Code,使用来存放帧头,帧尾和校验和。13个参数对应的是要发送的13个16位的温度值,也就是占用两个字节。可以考到这个数据串共占用3+13*2=29个字节。
我们在定义一个共同体,我们再了解一下共同体的区别。
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
基于上述的数据类型的建成,我们就开始讨论一下对接收和发送数据的编排构建了。
首先将数据长度的数组进行填充覆盖,就是将定义的发送数据帧长度的数组进行填充,我们这里填充值是FILL_VALUE = 0x00。
填充完毕后再利用定义的数据规则对上述填充后的数组进行原位覆盖,我们要用到将之前定义的数据结构体变量,那么我们就要声明一个新的结构体变量。
MSG_TypeDef Msg;
Msg.data[0].Int = Get_Tempture_Value(0);//ad1
我们将数据的第一位,转化成16进制数据存入uint16-t的数据类型中。
sendBuffer[2] = Msg.data[0].Ch[0];
sendBuffer[3] = Msg.data[0].Ch[1];
并将其拆分为一个低位和一个高位,装入输入的第2和第3位发送出去。
sendBuffer[0] = FRAME_START; // 帧头
sendBuffer[1] = 0x80|0x08; // 指令码
帧头和指令码各占用一位。
sendBuffer[FRAME_CHECKSUM] = CheckSum((uint8_t*)&sendBuffer[FRAME_CHECK_BEGIN],FRAME_CHECK_NUM); // 计算校验和
sendBuffer[FRAME_LENTH-1] = FRAME_END; // 加入帧尾
HAL_UART_Transmit(&huart3,(uint8_t *)&sendBuffer,FRAME_LENTH,0xffff); // 发送数据帧
void Transmit_Feedback(void)
{uint8_t i = 0;for(i=0;i<FRAME_LENTH;i++){sendBuffer[i] = FILL_VALUE; // 参数填充 0x00}Msg.data[0].Int = Get_Tempture_Value(0);//ad1Msg.data[1].Int = Get_Tempture_Value(1);//ad2 sendBuffer[0] = FRAME_START; // 帧头sendBuffer[1] = 0x80|0x08; // 指令码sendBuffer[2] = Msg.data[0].Ch[0];sendBuffer[3] = Msg.data[0].Ch[1]; sendBuffer[FRAME_CHECKSUM] = CheckSum((uint8_t*)&sendBuffer[FRAME_CHECK_BEGIN],FRAME_CHECK_NUM); // 计算校验和sendBuffer[FRAME_LENTH-1] = FRAME_END; // 加入帧尾HAL_UART_Transmit(&huart3,(uint8_t *)&sendBuffer,FRAME_LENTH,0xffff); // 发送数据帧
}
uint16_t Get_Tempture_Value(uint16_t adx)
{switch(adx){case ad1:return ROUND_TO_INT16_10(AdcTmpArray[0]);case ad2:return ROUND_TO_INT16_10(AdcTmpArray[1]);case ad3:return ROUND_TO_INT16_10(AdcTmpArray[2]);default:break; }return 0;
}
输出
void Output_Tempture(void)
{Adc_Handle();
#if NOUSECOM == 0Transmit_Feedback();
#else uint8_t i; for(i = 0; i < ChannelNum; i++){
// printf("通道%d value = %d -> %fV -> %f℃\n",i,AdcFilterArray[i]&0xFFF,AdcVoltArray[i],AdcTmpArray[i]);printf("%d=%f\n;",i,AdcTmpArray[i]);
// printf("当前电压为=%f, 母线电流为=%f;",AdcVoltArray[6],BusCurrent); }
#endif
}
这篇关于【STM32多路温控—第三章】ADC多通道采样,及数据上报的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!