求高手帮忙AI8H 12位ADC转换电压
我的ADC能正常读取到,使用的是unsigned int ,我的参考电压是2.5V读取出来的ADC数值*2500会超限,使用unsigned long数据就会变成0,求教怎么进行数据计算,unsigned int V,adc 使用V= (adc*2500/4096);无法实现计算#include "drive_ADC.h"#define BUBBLE_SORT //设置使用冒泡排序,去掉最高值、最低值,求中间平均值(不需要的话屏蔽此行)
#define SUM_LENGTH 16 /* 平均值采样次数 最大值16(不需要的话可将定义值改为 1 )*/
#ifdef BUBBLE_SORT//使用冒泡排序,去掉最高值、最低值,求中间平均值
int voladc1,voladc2,voladc3,voladc4;
u16 ADC_Buffer;
#endif
//void ADC_Isr() interrupt 5
//{
// ADC_CONTR &= ~0x20; //清中断标志
// voladc1=(ADC_RES << 8) | ADC_RESL;//adc读取
// ADC_CONTR |= 0x4a; //继续 AD 转换
//}
//符号 地址adc电源启动转换 转换结束 PWM触发 通道选择
//ADC_CONTR BCH ADC_POWER ADC_START ADC_FLAG ADC_EPWMT ADC_CHS
// 1 1 1 1 0000
void initADC(void)
{
P_SW2 |= 0x80; //使能访问 XFR,没有冲突不用关闭
ADCTIM = 0x3f; //设置 ADC 内部时序
ADCCFG = 0x20; //设置 ADC 时钟为系统时钟/2/1
//ADCCFG = 0x2f; //设置 ADC 时钟为系统时钟/2/16
ADC_CONTR = 0x80; //使能 ADC 模块
//EADC = 1; //使能 ADC 中断
EA = 1;
//ADC_CONTR |= 0x40; //启动 AD 转换
}
#ifdef BUBBLE_SORT//使用冒泡排序
//========================================================================
// 函数: void DataSwap(u16* data1, u16* data2)
// 描述: 数据交换函数。
// 参数: data1,data2 要交换的数据.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-9-27
// 备注:
//========================================================================
void DataSwap(u16* data1, u16* data2)
{
u16 temp;
temp = *data1;
*data1 = *data2;
*data2 = temp;
}
//========================================================================
// 函数: void BubbleSort(u16* pDataArry, u8 DataNum)
// 描述: 冒泡排序函数。
// 参数: pDataArry需要排序的数组,DataNum需要排序的数据个数.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-9-27
// 备注:
//========================================================================
void BubbleSort(u16* pDataArry, u8 DataNum)
{
bit flag;
u8 i,j;
for(i=0;i<DataNum-1;i++)
{
flag = 0;
for(j=0;j<DataNum-i-1;j++)
{
if(pDataArry > pDataArry)
{
flag = 1;
DataSwap(&pDataArry, &pDataArry);
}
}
if(!flag)//上一轮比较中不存在数据交换,则退出排序
{
break;
}
}
}
#endif
//========================================================================
// 函数: u16 Get_ADC12bitResult(u8 channel)) //channel = 0~15
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC, 0~15.
// 返回: 12位ADC结果.
// 版本: V1.0, 2016-4-28
//========================================================================
u16 Get_ADC12bitResult(u8 channel) //channel = 0~15
{
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel; //启动 AD 转换
_nop_();
_nop_();
_nop_();
while((ADC_CONTR & 0x20) == 0); //等待ADC结束
ADC_CONTR &= ~0x20; //清除ADC结束标志
return (((u16)ADC_RES << 8) | ADC_RESL);
}
/***********************************
查询方式做一次ADC, chn为通道号, chn=0~7对应P1.0~P1.7, chn=8~14对应P0.0~P0.6, chn=15对应BandGap电压.
***********************************/
u32 ADC_convert(u8 chn)
{
u16 j ;
//u32 h;
u8 k; //平均值滤波时使用
Get_ADC12bitResult(chn); //参数i=0~15,查询方式做一次ADC, 切换通道后第一次转换结果丢弃. 避免采样电容的残存电压影响.
Get_ADC12bitResult(chn); //参数i=0~15,查询方式做一次ADC, 切换通道后第二次转换结果丢弃. 避免采样电容的残存电压影响.
#ifdef BUBBLE_SORT//使用冒泡排序,去掉最高值、最低值,求中间平均值
for(k=0; k<16; k++) ADC_Buffer = Get_ADC12bitResult(chn);
BubbleSort(ADC_Buffer,16);//冒泡排序
for(k=4, j=0; k<12; k++) j += ADC_Buffer;//取中间8个数据
j = j / 8; // 求平均
#else //采样累加,求平均值(不需要的话可将 SUM_LENGTH 定义值改为 1 )
for(k=0, j=0; k<SUM_LENGTH; k++) j += Get_ADC12bitResult(chn); // 采样累加和 参数0~15,查询方式做一次ADC, 返回值就是结果
j = j / SUM_LENGTH; // 求平均
#endif
h= (j*2500/4096);
//debug("ADCV%02bd=%04u",chn,g);
debug("ADC%02bd=%u",chn,h);
return j;
}
在STC8H系列单片机中,12位ADC的转换结果范围为0到4095,对应输入电压的0到参考电压(Vref)。根据你的描述,参考电压为25V,因此ADC的每个LSB(最低有效位)对应的电压为:
\[ \text{LSB} = \frac{25V}{4096} \approx 0.0061V \]
你提到使用unsigned int类型存储ADC转换结果时,当ADC值为2500时会出现超限问题,而使用unsigned long类型时数据会变成0。这可能是由于数据类型转换或计算过程中出现了问题。以下是一些可能的原因及解决方案:
1. 数据类型选择
unsigned int在大多数8位单片机中通常是16位,范围为0到65535。对于12位ADC的转换结果(0到4095),unsigned int是足够的。然而,在进行计算时,如果中间结果超过了unsigned int的范围,可能会导致溢出或错误。
2. 计算顺序
在C语言中,整数除法的结果会被截断为整数。例如,2500 / 4096的结果是0,因为2500小于4096。为了避免这种情况,可以先进行乘法运算,再进行除法运算。例如:
c
unsigned int V = (adc2500) / 4096;
这样可以确保在除法之前,adc2500的结果足够大,避免被截断为0。
3. 使用浮点数
如果需要进行更精确的计算,可以使用浮点数。例如:
c
float V = (float)adc25.0 / 4096.0;
这样可以避免整数除法带来的精度损失。
4. 代码示例
以下是一个完整的代码示例,展示了如何正确计算ADC转换后的电压值:
c
include "driveADCh"
define BUBBLESORT // 设置使用冒泡排序,去掉最高值、最低值,求中间平均值(不需要的话屏蔽此行)
define SUMLENGTH 16 // 平均值采样次数 最大值16(不需要的话可将定义值改为 1 )
ifdef BUBBLESORT// 使用冒泡排序,去掉最高值、最低值,求中间平均值
int voladc1, voladc2, voladc3, voladc4;
u16 ADCBuffer;
endif
void ADCIsr() interrupt 5
{
ADCCONTR &= ~0x20; // 清中断标志
voladc1 = (ADCRESarr)
{
u16 temp = arr;
arr = arr;
arr = temp;
}
}
}
}
u16 CalculateAverage(u16 arr[], int n)
{
BubbleSort(arr, n);
u16 sum = 0;
for (int i = 1; i < n-1; i++) // 去掉最高值和最低值
{
sum += arr;
}
return sum / (n-2);
}
endif
在main函数中,你可以使用CalculateAverage函数来计算平均值:
c
ifdef BUBBLESORT
u16 adcvalues;
// 填充adcvalues数组
u16 averageadc = CalculateAverage(adcvalues, SUMLENGTH);
unsigned int averagevoltage = CalculateVoltage(averageadc);
endif
总结
通过合理选择数据类型、调整计算顺序以及使用浮点数,可以避免ADC转换结果计算中的问题。此外,冒泡排序和平均值计算可以帮助你获得更稳定的ADC读数。希望这些建议能帮助你解决当前的问题。
[本文内容由国芯人工智能辅助生成,仅供参考]
等号前后数据类型必须匹配
unsigned int V;
unsigned int adc;
V=(unsigned int) ((unsigned long)adc*2500UL/4096UL);
j = (uint)((ulong)j * 119 / Bandgap); //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V
我一般这样计算 不是4096,是4096UL就可以了 DebugLab 发表于 2025-4-21 15:39
等号前后数据类型必须匹配
unsigned int V;
感谢,用了你的方法,终于可以了 国芯人工智能 发表于 2025-4-21 15:18
在STC8H系列单片机中,12位ADC的转换结果范围为0到4095,对应输入电压的0到参考电压(Vref)。根据你的描述 ...
非常感谢,问题解决了 18344371880 发表于 2025-4-21 17:26
不是4096,是4096UL就可以了
非常感谢 haiyang201 发表于 2025-4-21 16:07
j = (uint)((ulong)j * 119 / Bandgap); //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V
我一般这 ...
非常感谢,用了你这种写法终于正常了
页:
[1]