【STM32多路温控—第三章】ADC多通道采样,及数据上报

2023-10-12 20:39

本文主要是介绍【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多通道采样,及数据上报的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

Python给Excel写入数据的四种方法小结

《Python给Excel写入数据的四种方法小结》本文主要介绍了Python给Excel写入数据的四种方法小结,包含openpyxl库、xlsxwriter库、pandas库和win32com库,具有... 目录1. 使用 openpyxl 库2. 使用 xlsxwriter 库3. 使用 pandas 库

SpringBoot定制JSON响应数据的实现

《SpringBoot定制JSON响应数据的实现》本文主要介绍了SpringBoot定制JSON响应数据的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们... 目录前言一、如何使用@jsonView这个注解?二、应用场景三、实战案例注解方式编程方式总结 前言

Python实现多路视频多窗口播放功能

《Python实现多路视频多窗口播放功能》这篇文章主要为大家详细介绍了Python实现多路视频多窗口播放功能的相关知识,文中的示例代码讲解详细,有需要的小伙伴可以跟随小编一起学习一下... 目录一、python实现多路视频播放功能二、代码实现三、打包代码实现总结一、python实现多路视频播放功能服务端开

使用Python在Excel中创建和取消数据分组

《使用Python在Excel中创建和取消数据分组》Excel中的分组是一种通过添加层级结构将相邻行或列组织在一起的功能,当分组完成后,用户可以通过折叠或展开数据组来简化数据视图,这篇博客将介绍如何使... 目录引言使用工具python在Excel中创建行和列分组Python在Excel中创建嵌套分组Pyt

在Rust中要用Struct和Enum组织数据的原因解析

《在Rust中要用Struct和Enum组织数据的原因解析》在Rust中,Struct和Enum是组织数据的核心工具,Struct用于将相关字段封装为单一实体,便于管理和扩展,Enum用于明确定义所有... 目录为什么在Rust中要用Struct和Enum组织数据?一、使用struct组织数据:将相关字段绑

在Mysql环境下对数据进行增删改查的操作方法

《在Mysql环境下对数据进行增删改查的操作方法》本文介绍了在MySQL环境下对数据进行增删改查的基本操作,包括插入数据、修改数据、删除数据、数据查询(基本查询、连接查询、聚合函数查询、子查询)等,并... 目录一、插入数据:二、修改数据:三、删除数据:1、delete from 表名;2、truncate

Java实现Elasticsearch查询当前索引全部数据的完整代码

《Java实现Elasticsearch查询当前索引全部数据的完整代码》:本文主要介绍如何在Java中实现查询Elasticsearch索引中指定条件下的全部数据,通过设置滚动查询参数(scrol... 目录需求背景通常情况Java 实现查询 Elasticsearch 全部数据写在最后需求背景通常情况下

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内