OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2417|回复: 5

想问下关于电压采集代码的问题

[复制链接]

1

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2019-7-8
在线时间
8 小时
发表于 2020-3-12 13:08:23 | 显示全部楼层 |阅读模式
1金钱
这是一段论坛上的代码adcx=Get_Adc_Average(ADC_Channel_1,10);                //得到ADC转换值         
                        temp=(float)(adcx*(3.022/1022))/(4.620/6.609);                  //是10位adc,不是12位的adc得到ADC电压值,(4.620/6.609)是电阻分压系数
                        adcx=temp;
                        OLED_ShowNum(5+65,30,temp,1,16);
//                         LCD_ShowxNum(124,110,temp,1,16,0);             //显示电压值整数部分
                        temp-=adcx;
                        temp*=1000;//这一部分处理后用来显示小数
                        OLED_ShowString(5+75,30,".",16);
                        OLED_ShowNum(5+80,30,temp,3,16);
                        OLED_ShowString(5+105,30,"mA",16);
                        OLED_Refresh_Gram();
//                        LCD_ShowxNum(140,110,temp,3,16,0X80);         //显示电压值的小数部分
其实这段代码是有缺陷的,但是说实话,我没想明白怎么解决
这段代码的问题就在于不能显示3.0v电压(小数位并不能自动补0),假如我现在要显示3.099v电压,那么真实在oled上显示就是3._99v电压,那么该如何解决呢


然后这段代码处理起来还有精度问题,现在测量在3.7几是准确的,但是有0.04v跳动,请问滤波方面有什么好的建议,单片机性能较差,内存也比较少,用不了sprintf之类的函数,目前使用的是连续adc采值+平均值处理数据跳动在7个点以内,在电路上,电阻分压有加0.1uf电容,使用4位电阻均没超过10k

我使用的是stm8s001j3m3,虽然不该在stm32板块发,但是由于这段代码在处理上和stm32一摸一样,所以到32板块来发帖,毕竟学stm8也是为了快点入门32嘛,嘿嘿

                                                                                                                                                                                                                                      ---------c语言菜鸡

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

211

帖子

0

精华

高级会员

Rank: 4

积分
833
金钱
833
注册时间
2019-12-17
在线时间
157 小时
发表于 2020-3-12 14:25:50 | 显示全部楼层
小数前面的零可以先转化成字符串再显示,如果用不了标准库的sprintf就自己手动转化一下好了
滤波的话可以考虑一下中值滤波(例:取五个值取他们的中位数作为有效值),或者使用中位平均滤波(例:取6个数,去掉最大最小值,取剩下的值的平均值)。
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2019-7-8
在线时间
8 小时
 楼主| 发表于 2020-3-12 23:42:18 | 显示全部楼层
y284858 发表于 2020-3-12 14:25
小数前面的零可以先转化成字符串再显示,如果用不了标准库的sprintf就自己手动转化一下好了
滤波的话可以 ...

刚入门几天,以前只会写51,常见的变量我会转,但是,在程序中用的是uint16_t(只知道这个是整形数据,只占16个字节,能放得下1024个数,如果是uint8_t得话最大只能放下啊256个数),这个由于在书上没有见过,所以在你说过以后自己尝试去转,编译会报错,,中值和中位值的代码量应该比平均的更多,单片机资源有限,有好的写法吗,我自己尝试写了下感觉量有点大。。。。哎。。。内存太小搞得我写代码比花钱还扣,但是觉得又不是坏事
我再这放下我的代码
Conversion_Value_Tmp = Battery_Check_Read();
OLED_ShowNum(0,0,Conversion_Value_Tmp,4,16);
nBattery_Check_Value=((float)Conversion_Value_Tmp/1022*3.02)*6.61/4.62;
OLED_ShowNum(52,2,(uint16_t)nBattery_Check_Value,1,16);
Conversion_Value_Tmp=(uint16_t)nBattery_Check_Value;
nBattery_Check_Value-=Conversion_Value_Tmp;
nBattery_Check_Value*=1000;
OLED_ShowString(64,2,".");
OLED_ShowNum(72,2,(uint16_t)nBattery_Check_Value,3,16);
这是用来处理电压小数得
类型太多,我已经转得老眼昏花了
然后是均值滤波
  uint16_t nBattery_average_Value = 0;
  uint16_t nNum = 0;
  for(nNum =0; nNum < BATTERY_CHECK_COUNT_PER_COLLECT; nNum++)
  {
    ADC1_StartConversion();
    nBattery_average_Value += ADC1_GetConversionValue();   
  }
  nBattery_average_Value /= BATTERY_CHECK_COUNT_PER_COLLECT;
还有比这更好的吗
回复

使用道具 举报

6

主题

211

帖子

0

精华

高级会员

Rank: 4

积分
833
金钱
833
注册时间
2019-12-17
在线时间
157 小时
发表于 2020-3-13 10:48:29 | 显示全部楼层
xda 发表于 2020-3-12 23:42
刚入门几天,以前只会写51,常见的变量我会转,但是,在程序中用的是uint16_t(只知道这个是整形数据,只 ...

uint16_t 是65536个数
看你的代码你需要的是三位小数精度,需要的小数部分你已经转换成整数了,那么现在就是将小数部分转换成字符串
首先定义一个字符串数组 char data[n+1] ={0}; n在这里是你要转化的位数。
然后使用for循环转换
uint16_t buf = Conversion_Value_Tmp;
char string_data[n+1] ={0};

forint i = n ,j = n- 2;i>0;i--,j--)
{
    string_data[j] = (buf%10)+'0'; //最低位转换为字符保存
    buf/= 10 ;              //除以十清除最低位
}
    string_data[n-1]='\0';         //标记字符串结束



滤波如果做中位值代码量相差并不大,你可以百度一下排序算法,排完序选择正中间的数就可以了或者你不做中值也可以在你的滤波里面加入一个去除最大最小值,然后适当的扩大一下采样个数
回复

使用道具 举报

1

主题

3

帖子

0

精华

新手上路

积分
24
金钱
24
注册时间
2019-7-8
在线时间
8 小时
 楼主| 发表于 2020-3-13 21:09:32 | 显示全部楼层
y284858 发表于 2020-3-13 10:48
uint16_t 是65536个数
看你的代码你需要的是三位小数精度,需要的小数部分你已经转换成整数 ...

大佬,那个i是做什么的呢,没看太明白,嘿嘿,你之前说的意思是需要我在已经做了小数处理的基础上再加上你的代码吧,代码我尝试修改了,但是没跑起来,不知道是哪里错了
Conversion_Value_Tmp = Battery_Check_Read();
OLED_ShowNum(0,0,Conversion_Value_Tmp,4,16);
nBattery_Check_Value=((float)Conversion_Value_Tmp/1022*3.02)*6.61/4.62-0.04;
OLED_ShowNum(52,2,(uint16_t)nBattery_Check_Value,1,16);
Conversion_Value_Tmp=(uint16_t)nBattery_Check_Value;
nBattery_Check_Value-=Conversion_Value_Tmp;
nBattery_Check_Value*=1000;
buf = Conversion_Value_Tmp;
OLED_ShowString(64,2,".");
for(int i=n,j=n-2;i>0;i--,j--)//n我就放在开头的宏定义了给定值为3
{
    string_data[j] = (buf%10)+'0';  //最低位转换为字符保存
    buf/= 10;              //除以十清除最低位
}
    string_data[n-1]='\0';        //标记字符串结束

OLED_ShowNum(72,2,string_data[n],3,16);

但是显示不对,是我哪里做错了呢,可以再麻烦大佬帮我看一下吗
回复

使用道具 举报

6

主题

211

帖子

0

精华

高级会员

Rank: 4

积分
833
金钱
833
注册时间
2019-12-17
在线时间
157 小时
发表于 2020-3-16 09:40:55 | 显示全部楼层
xda 发表于 2020-3-13 21:09
大佬,那个i是做什么的呢,没看太明白,嘿嘿,你之前说的意思是需要我在已经做了小数处理的基础上再加上 ...

i是用做计数的,你需要转换3位结果所以是3,
for(int i=n,j=n-2;i>0;i--,j--) //这里我打错了,j应该等于n-1
另外你显示错误方便的话发一下图像,不行的话详细描述一下也可以。
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-22 16:25

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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