找回密码
 立即注册
查看: 95|回复: 8

求高手帮忙AI8H 12位ADC转换电压

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-05-01 10:15:31
已绑定手机

3

主题

11

回帖

215

积分

中级会员

积分
215
发表于 2025-4-21 15:12:30 | 显示全部楼层 |阅读模式
我的ADC能正常读取到,使用的是unsigned int ,我的参考电压是2.5V读取出来的ADC数值*2500会超限,使用unsigned long数据就会变成0,求教怎么进行数据计算,unsigned int V,adc 使用V= (adc*2500/4096);无法实现计算
  1. #include "drive_ADC.h"
  2. #define BUBBLE_SORT     //设置使用冒泡排序,去掉最高值、最低值,求中间平均值(不需要的话屏蔽此行)
  3. #define SUM_LENGTH        16        /* 平均值采样次数 最大值16(不需要的话可将定义值改为 1 )*/
  4. #ifdef BUBBLE_SORT  //使用冒泡排序,去掉最高值、最低值,求中间平均值
  5. int voladc1,voladc2,voladc3,voladc4;
  6. u16 ADC_Buffer[16];
  7. #endif
  8. //void ADC_Isr() interrupt 5
  9. //{
  10. //    ADC_CONTR &= ~0x20; //清中断标志
  11. //    voladc1=(ADC_RES << 8) | ADC_RESL;//adc读取
  12. //    ADC_CONTR |= 0x4a; //继续 AD 转换
  13. //}
  14. //符号                地址  adc电源  启动转换 转换结束 PWM触发   通道选择
  15. //ADC_CONTR BCH ADC_POWER ADC_START ADC_FLAG ADC_EPWMT ADC_CHS
  16. //                                1                        1                        1                1                0000
  17. void initADC(void)
  18. {
  19.     P_SW2 |= 0x80; //使能访问 XFR,没有冲突不用关闭
  20.     ADCTIM = 0x3f; //设置 ADC 内部时序
  21.     ADCCFG = 0x20; //设置 ADC 时钟为系统时钟/2/1
  22.     //ADCCFG = 0x2f; //设置 ADC 时钟为系统时钟/2/16
  23.     ADC_CONTR = 0x80; //使能 ADC 模块
  24.     //EADC = 1; //使能 ADC 中断
  25.     EA = 1;
  26.     //ADC_CONTR |= 0x40; //启动 AD 转换
  27. }
  28. #ifdef BUBBLE_SORT  //使用冒泡排序
  29. //========================================================================
  30. // 函数: void DataSwap(u16* data1, u16* data2)
  31. // 描述: 数据交换函数。
  32. // 参数: data1,data2 要交换的数据.
  33. // 返回: none.
  34. // 版本: VER1.0
  35. // 日期: 2021-9-27
  36. // 备注:
  37. //========================================================================
  38. void DataSwap(u16* data1, u16* data2)
  39. {
  40.         u16 temp;
  41.         temp = *data1;
  42.         *data1 = *data2;
  43.         *data2 = temp;
  44. }
  45. //========================================================================
  46. // 函数: void BubbleSort(u16* pDataArry, u8 DataNum)
  47. // 描述: 冒泡排序函数。
  48. // 参数: pDataArry需要排序的数组,DataNum需要排序的数据个数.
  49. // 返回: none.
  50. // 版本: VER1.0
  51. // 日期: 2021-9-27
  52. // 备注:
  53. //========================================================================
  54. void BubbleSort(u16* pDataArry, u8 DataNum)
  55. {
  56.         bit flag;
  57.         u8 i,j;
  58.         for(i=0;i<DataNum-1;i++)
  59.         {
  60.                 flag = 0;
  61.                 for(j=0;j<DataNum-i-1;j++)
  62.                 {
  63.                         if(pDataArry[j] > pDataArry[j+1])
  64.                         {
  65.                                 flag = 1;
  66.                                 DataSwap(&pDataArry[j], &pDataArry[j+1]);
  67.                         }
  68.                 }
  69.                 if(!flag)  //上一轮比较中不存在数据交换,则退出排序
  70.                 {
  71.                         break;
  72.                 }
  73.         }
  74. }
  75. #endif
  76. //========================================================================
  77. // 函数: u16 Get_ADC12bitResult(u8 channel))        //channel = 0~15
  78. // 描述: 查询法读一次ADC结果.
  79. // 参数: channel: 选择要转换的ADC, 0~15.
  80. // 返回: 12位ADC结果.
  81. // 版本: V1.0, 2016-4-28
  82. //========================================================================
  83. u16        Get_ADC12bitResult(u8 channel)        //channel = 0~15
  84. {
  85.         ADC_RES = 0;
  86.         ADC_RESL = 0;
  87.     ADC_CONTR = (ADC_CONTR & 0xF0) | 0x40 | channel;    //启动 AD 转换
  88.     _nop_();
  89.     _nop_();
  90.     _nop_();
  91.     while((ADC_CONTR & 0x20) == 0);   //等待ADC结束
  92.     ADC_CONTR &= ~0x20;     //清除ADC结束标志
  93.     return (((u16)ADC_RES << 8) | ADC_RESL);
  94. }
  95. /***********************************
  96. 查询方式做一次ADC, chn为通道号, chn=0~7对应P1.0~P1.7, chn=8~14对应P0.0~P0.6, chn=15对应BandGap电压.
  97. ***********************************/
  98. u32 ADC_convert(u8 chn)
  99. {
  100.         u16        j ;
  101.         //u32 h;
  102.         u8        k;                //平均值滤波时使用
  103.         Get_ADC12bitResult(chn);                //参数i=0~15,查询方式做一次ADC, 切换通道后第一次转换结果丢弃. 避免采样电容的残存电压影响.
  104.         Get_ADC12bitResult(chn);                //参数i=0~15,查询方式做一次ADC, 切换通道后第二次转换结果丢弃. 避免采样电容的残存电压影响.
  105. #ifdef BUBBLE_SORT  //使用冒泡排序,去掉最高值、最低值,求中间平均值
  106.         for(k=0; k<16; k++)        ADC_Buffer[k] = Get_ADC12bitResult(chn);
  107.         BubbleSort(ADC_Buffer,16);  //冒泡排序
  108.         for(k=4, j=0; k<12; k++) j += ADC_Buffer[k];  //取中间8个数据
  109.         j = j / 8;                // 求平均
  110. #else   //采样累加,求平均值(不需要的话可将 SUM_LENGTH 定义值改为 1 )
  111.         for(k=0, j=0; k<SUM_LENGTH; k++)        j += Get_ADC12bitResult(chn);        // 采样累加和 参数0~15,查询方式做一次ADC, 返回值就是结果
  112.         j = j / SUM_LENGTH;                // 求平均
  113. #endif
  114.         h= (j*2500/4096);
  115. //debug("ADCV%02bd=%04u",chn,g);
  116. debug("ADC%02bd=%u",chn,h);
  117. return j;
  118. }
复制代码


回复

使用道具 举报 送花

3

主题

1160

回帖

1031

积分

等待验证会员

积分
1031
发表于 2025-4-21 15:18:00 | 显示全部楼层
在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。为了避免这种情况,可以先进行乘法运算,再进行除法运算。例如:
  1. c
  2. unsigned int V = (adc  2500) / 4096;
复制代码

这样可以确保在除法之前,adc  2500的结果足够大,避免被截断为0。

3. 使用浮点数
如果需要进行更精确的计算,可以使用浮点数。例如:
  1. c
  2. float V = (float)adc  25.0 / 4096.0;
复制代码

这样可以避免整数除法带来的精度损失。

4. 代码示例
以下是一个完整的代码示例,展示了如何正确计算ADC转换后的电压值:
  1. c
  2. include "driveADCh"
  3. define BUBBLESORT     // 设置使用冒泡排序,去掉最高值、最低值,求中间平均值(不需要的话屏蔽此行)
  4. define SUMLENGTH 16   // 平均值采样次数 最大值16(不需要的话可将定义值改为 1 )
  5. ifdef BUBBLESORT  // 使用冒泡排序,去掉最高值、最低值,求中间平均值
  6. int voladc1, voladc2, voladc3, voladc4;
  7. u16 ADCBuffer[16];
  8. endif
  9. void ADCIsr() interrupt 5
  10. {
  11.     ADCCONTR &= ~0x20; // 清中断标志
  12.     voladc1 = (ADCRES  arr[j+1])
  13.             {
  14.                 u16 temp = arr[j];
  15.                 arr[j] = arr[j+1];
  16.                 arr[j+1] = temp;
  17.             }
  18.         }
  19.     }
  20. }
  21. u16 CalculateAverage(u16 arr[], int n)
  22. {
  23.     BubbleSort(arr, n);
  24.     u16 sum = 0;
  25.     for (int i = 1; i < n-1; i++) // 去掉最高值和最低值
  26.     {
  27.         sum += arr[i];
  28.     }
  29.     return sum / (n-2);
  30. }
  31. endif
复制代码

在main函数中,你可以使用CalculateAverage函数来计算平均值:
  1. c
  2. ifdef BUBBLESORT
  3.     u16 adcvalues[SUMLENGTH];
  4.     // 填充adcvalues数组
  5.     u16 averageadc = CalculateAverage(adcvalues, SUMLENGTH);
  6.     unsigned int averagevoltage = CalculateVoltage(averageadc);
  7. endif
复制代码

总结
通过合理选择数据类型、调整计算顺序以及使用浮点数,可以避免ADC转换结果计算中的问题。此外,冒泡排序和平均值计算可以帮助你获得更稳定的ADC读数。希望这些建议能帮助你解决当前的问题。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:423
  • 最近打卡:2025-05-01 07:10:25
已绑定手机

76

主题

4833

回帖

8343

积分

超级版主

DebugLab

积分
8343
发表于 2025-4-21 15:39:55 | 显示全部楼层

等号前后数据类型必须匹配

unsigned int V;

unsigned int adc;

V=(unsigned int) ((unsigned long)adc*2500UL/4096UL);


DebugLab
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:297
  • 最近打卡:2025-05-01 06:53:32
已绑定手机

4

主题

339

回帖

1558

积分

金牌会员

积分
1558
发表于 2025-4-21 16:07:34 | 显示全部楼层
                j = (uint)((ulong)j * 119 / Bandgap);          //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V
我一般这样计算
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:454
  • 最近打卡:2025-05-01 07:53:22

28

主题

162

回帖

1879

积分

金牌会员

积分
1879
发表于 2025-4-21 17:26:41 | 显示全部楼层
不是4096,是4096UL就可以了
回复 支持 1 反对 0

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-05-01 10:15:31
已绑定手机

3

主题

11

回帖

215

积分

中级会员

积分
215
发表于 2025-4-22 11:45:43 | 显示全部楼层
Debu*** 发表于 2025-4-21 15:39
等号前后数据类型必须匹配

unsigned int V;

感谢,用了你的方法,终于可以了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-05-01 10:15:31
已绑定手机

3

主题

11

回帖

215

积分

中级会员

积分
215
发表于 2025-4-22 11:46:41 | 显示全部楼层
国芯人*** 发表于 2025-4-21 15:18
在STC8H系列单片机中,12位ADC的转换结果范围为0到4095,对应输入电压的0到参考电压(Vref)。根据你的描述 ...

非常感谢,问题解决了
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-05-01 10:15:31
已绑定手机

3

主题

11

回帖

215

积分

中级会员

积分
215
发表于 2025-4-22 11:46:56 | 显示全部楼层
183443*** 发表于 2025-4-21 17:26
不是4096,是4096UL就可以了

非常感谢
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:46
  • 最近打卡:2025-05-01 10:15:31
已绑定手机

3

主题

11

回帖

215

积分

中级会员

积分
215
发表于 2025-4-22 11:48:00 | 显示全部楼层
haiya*** 发表于 2025-4-21 16:07
j = (uint)((ulong)j * 119 / Bandgap);          //计算外部电压, Bandgap为1.19V, 测电压分辨率0.01V
我一般这 ...

非常感谢,用了你这种写法终于正常了
回复 支持 反对

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-5-1 19:54 , Processed in 0.160908 second(s), 101 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表