DYyanfa 2024-03-27 19:42 采纳率: 31.3%
浏览 11

单片机串口发送的采集电压值不准确

STC8g1k08单片机进行电池电压采集,之前因为抖动,输入电压值稳定情况下,逻辑分析仪采集的值每次都有变动,现在修改程序,加入了平均值,出现了新的问题,就是uart串口发送的数据不准确了,当前输入电压为2.2v,串口接收到的数据应该是0x16才正确


#define  _ADC_C
#include "ADC.h"
#include "config.h"
#include "Uart.h"
#include "string.h"

#define ADC_RES_MAX 1024  // ADC采样最大值
#define V_REF (3.3)        // 参考电压为3.3V
#define V_BAT_MAX (2.8)     // 电池最大电压为2.8V
#define V_BAT_MIN (1.8)     // 电池最小电压为1.8V
#define V_BAT_WARN (2.1)    // 电池电量过低警告阈值为2.1V

unsigned int ADC_Value;  // 定义全局变量,用于存储采样结果
unsigned char cnt = 0;  //
unsigned int AdcBuff[] = {0,0,0,0,0,0,0,0,0,0};

void ADC_Init() 
{
    P_SW2 |= 0x80;
    ADCTIM = 0x2A; //设置 ADC 内部时序
    P_SW2 &= 0x7f;
    ADCCFG = 0x20; //设置 ADC 时钟为系统时钟/2,右对齐
    ADC_CONTR = 0x80; //使能 ADC 模块
}

void ADC_ISR() interrupt 5 
{
    ADC_Value = (unsigned int)(ADC_RES << 8) + (unsigned int)ADC_RESL;
    if(cnt < 10)
    {
        AdcBuff[cnt] = ADC_Value;
        cnt++;
    }
    ADC_CONTR &= ~0x20; //中断标志位清0
    if(cnt == 10)
    {
        cnt = 0;
        memset(AdcBuff,0,sizeof(AdcBuff));
    }
}

void Delay1ms(void)    
{
    unsigned char data i, j;

    _nop_();
    _nop_();
    _nop_();
    i = 11;
    j = 190;
    do
    {
        while (--j);
    } while (--i);
}

void ADC_BATTERY() 
{
    unsigned int i=0,j=0,t=0;
//    unsigned char battery_percent = 0;  // 定义电量百分比变量
    float adc_res,battery_percent,ave;
    float v_bat;
    ADC_CONTR &= 0xf0;    //底四位清零
    ADC_CONTR |= 0x0C;    //置通道12
    ADC_CONTR |= 0x40;  // 启动ADC转换
    Delay1ms();
//    while(cnt < 10);
    if(cnt == 0)
    {
        return;
    }
    for(j=0;j<9;j++)    //将数组由小到大排序
        for(i=0;i<9-j;i++)
            if(AdcBuff[i]>AdcBuff[i+1])
            {
                t=AdcBuff[i];
                AdcBuff[i] = AdcBuff[i+1];
                AdcBuff[i+1] = t;
            }
    ave = (AdcBuff[3]+AdcBuff[4]+AdcBuff[5]+AdcBuff[6]) / 4;
    adc_res = (float)ave * V_REF / ADC_RES_MAX;// 计算ADC被转换通道的输入电压
    v_bat = adc_res * V_BAT_MAX / V_REF;// 计算电池电压值
    battery_percent = (v_bat - V_BAT_MIN)  / (V_BAT_MAX - V_BAT_MIN) * 100.0;// 计算电池电量百分比
    UartSend(adc_res * 10);
}
  • 写回答

2条回答 默认 最新

  • 专家-皆知 2024-03-27 19:42
    关注

    引自免费微信小程序:皆我百晓生

    从您提供的代码中,我注意到几个可能影响UART发送数据准确性的问题:

    1. ADC_ISR()函数中,您计算了ADC的值,并将其存储在AdcBuff数组中。然后,您使用UartSend()函数发送数据。但是,UartSend()函数的参数应该是一个字符数组,而不是一个浮点数。因此,您需要将ADC_Value转换为字符数组,并使用UartSend()函数发送它。

    2. ADC_BATTERY()函数中,您计算了ADC的值,并将其存储在AdcBuff数组中。然后,您使用UartSend()函数发送数据。但是,您需要确保在发送数据之前,将AdcBuff数组中的数据格式化为字符串。这样,您可以将整个字符串发送,而不是一个浮点数。

    以下是修改后的代码:

    #define _ADC_C
    #include "ADC.h"
    #include "config.h"
    #include "Uart.h"
    #include "string.h"
    
    #define ADC_RES_MAX 1024  // ADC采样最大值
    #define V_REF (3.3)        // 参考电压为3.3V
    #define V_BAT_MAX (2.8)     // 电池最大电压为2.8V
    #define V_BAT_MIN (1.8)     // 电池最小电压为1.8V
    #define V_BAT_WARN (2.1)    // 电池电量过低警告阈值为2.1V
    
    unsigned int ADC_Value;  // 定义全局变量,用于存储采样结果
    unsigned char cnt = 0;  //
    unsigned int AdcBuff[] = {0,0,0,0,0,0,0,0,0,0};
    
    void ADC_Init() 
    {
        P_SW2 |= 0x80;
        ADCTIM = 0x2A; //设置 ADC 内部时序
        P_SW2 &= 0x7f;
        ADCCFG = 0x20; //设置 ADC 时钟为系统时钟/2,右对齐
        ADC_CONTR = 0x80; //使能 ADC 模块
    }
    
    void ADC_ISR() interrupt 5 
    {
        ADC_Value = (unsigned int)(ADC_RES << 8) + (unsigned int)ADC_RESL;
        if(cnt < 10)
        {
            AdcBuff[cnt] = ADC_Value;
            cnt++;
        }
        ADC_CONTR &= ~0x20; //中断标志位清0
        if(cnt == 10)
        {
            cnt = 0;
            memset(AdcBuff,0,sizeof(AdcBuff));
        }
    }
    
    void Delay1ms(void)    
    {
        unsigned char data i, j;
    
        _nop_();
        _nop_();
        _nop_();
        i = 11;
        j = 190;
        do
        {
            while (--j);
        } while (--i);
    }
    
    void ADC_BATTERY() 
    {
        unsigned int i=0,j=0,t=0;
        //    unsigned char battery_percent = 0;  // 定义电量百分比变量
        float adc_res,battery_percent,ave;
        float v_bat;
        ADC_CONTR &= 0xf0;    //底四位清零
        ADC_CONTR |= 0x0C;    //置通道12
        ADC_CONTR |= 0x40;  // 启动ADC转换
        Delay1ms();
        //    while(cnt < 10);
        if(cnt == 0)
        {
            return;
        }
        for(j=0;j<9;j++)    //将数组由小到大排序
            for(i=0;i<9-j;i++)
                if(AdcBuff[i]>AdcBuff[i+1])
                {
                    t=AdcBuff[i];
                    AdcBuff[i] = AdcBuff[i+1];
                    AdcBuff[i+1] = t;
                }
        average = (AdcBuff[3]+AdcBuff[4]+AdcBuff[5]+AdcBuff[6]) / 4;
        adc_res = (float)average * V_REF / ADC_RES_MAX;// 计算ADC被转换通道的输入电压
        v_bat = adc_res * V_BAT_MAX / V_REF;// 计算电池电压值
        battery_percent = (v_bat - V_BAT_MIN)  / (V_BAT_MAX - V_BAT_MIN) * 100.0;// 计算电池电量百分比
        UartSend(adc_res * 10);
    }
    

    修改后的代码应该可以解决您提到的问题。但是,为了确保问题已经解决,您需要实际测试这些代码并观察结果。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 3月27日

悬赏问题

  • ¥15 怎么把512还原为520格式
  • ¥15 MATLAB的动态模态分解出现错误,以CFX非定常模拟结果为快照
  • ¥15 求高通平台Softsim调试经验
  • ¥15 canal如何实现将mysql多张表(月表)采集入库到目标表中(一张表)?
  • ¥15 wpf ScrollViewer实现冻结左侧宽度w范围内的视图
  • ¥15 栅极驱动低侧烧毁MOSFET
  • ¥30 写segy数据时出错3
  • ¥100 linux下qt运行QCefView demo报错
  • ¥50 F1C100S下的红外解码IR_RX驱动问题
  • ¥20 基于matlab的航迹融合 航迹关联 航迹插补