Emmetttttt 发表于 2024-11-7 16:14:28

关于AI8G1K08A-8Pin的ADC采样问题

本帖最后由 DebugLab 于 2024-11-7 21:16 编辑

用AI8G1K08A-8pin进行对母线高电压与IGBT温度采集

但是不知道为什么偶尔会出现adc采集不到的情况导致传出4096的情况
对电压采集的频率是10KHz,温度采集的频率是1KHz,下面是全部代码,求大佬解答{:5_300:}

#include      "config.h"
#include      "STC8G_H_ADC.h"
#include      "STC8G_H_GPIO.h"
#include      "STC8G_H_Delay.h"
#include      "STC8G_H_UART.h"
#include      "STC8G_H_NVIC.h"
#include      "STC8G_H_Switch.h"
#include         "STC8G_H_Timer.h"
#include      <math.h>

/***************   宏声明      ******************/
#define HVMAX      680

/*************      本地常量声明      **************/
u32 VCC = 5.0;

/*************      本地变量声明      **************/
struct Flag_bit
{
      u8 VoltAcqError : 1;                //电压采集出错
      u8 TempAcqError : 1;                //温度采集出错
      u8 Keep3 : 1;                              //保留位
      u8 Keep4 : 1;                              //保留位
};

union Flag_set
{
      u8 all;
      struct Flag_bit fbit;
};

typedef struct
{
      u8 IGBTTemperature;                        //温度
      u8 BUSVoltage;                              //电压
      union Flag_set Flagbit;                //状态
}PowerUartData;

PowerUartData pwruartdata;

u8 div_01ms = 0;
u8 div_1ms = 0;
u8 div_10ms = 0;
u8 div_100ms = 0;
u8 div_1s = 0;

int vcatch = 0;
int lastvcatch = 0;
/*************      本地函数声明      **************/

/*************外部函数和变量声明 *****************/

/******************* IO配置函数 *******************/
void GPIO_config(void)
{
      GPIO_InitTypeDef      GPIO_InitStructure;                //结构定义
      //AD口设置为输入口
      GPIO_InitStructure.Pin= GPIO_Pin_4 | GPIO_Pin_5;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_HighZ;                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P5,&GPIO_InitStructure);      //初始化
      
      GPIO_InitStructure.Pin= GPIO_Pin_3;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_OUT_PP;                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);      //初始化
      
      GPIO_InitStructure.Pin= GPIO_Pin_2;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_OUT_PP;                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);      //初始化

      GPIO_InitStructure.Pin= GPIO_Pin_1;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_PullUp;                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);      //初始化

      GPIO_InitStructure.Pin= GPIO_Pin_0;                //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
      GPIO_InitStructure.Mode = GPIO_OUT_PP;                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
      GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);      //初始化
      P33 = 0;
      P32 = 0;
      P30 = 0;
}

/******************* 定时器1配置函数 *******************/
void TIMER0_config(void)
{
      TIM_InitTypeDef                TIM_InitStructure;                                                //结构定义

      //定时器0做16位自动重装, 中断频率为10KHZ
      TIM_InitStructure.TIM_Mode      = TIM_16BitAutoReload;      //指定工作模式,   TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
      TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T;                        //指定时钟源,   TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
      TIM_InitStructure.TIM_ClkOut    = DISABLE;                              //是否输出高速脉冲, ENABLE或DISABLE
      TIM_InitStructure.TIM_Value   = 65536UL - (MAIN_Fosc / 10000UL);                //初值,
      TIM_InitStructure.TIM_Run       = ENABLE;                              //是否初始化后启动定时器, ENABLE或DISABLE
      Timer_Inilize(Timer0,&TIM_InitStructure);                              //初始化Timer0          Timer0,Timer1,Timer2,Timer3,Timer4
      NVIC_Timer0_Init(ENABLE,Priority_1);                //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

/******************* AD配置函数 *******************/
void ADC_config(void)
{
      ADC_InitTypeDef                ADC_InitStructure;                //结构定义

      ADC_InitStructure.ADC_SMPduty   = 31;                //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
      ADC_InitStructure.ADC_CsSetup   = 0;                //ADC 通道选择时间控制 0(默认),1
      ADC_InitStructure.ADC_CsHold    = 2;                //ADC 通道选择保持时间控制 0,1(默认),2,3
      ADC_InitStructure.ADC_Speed   = ADC_SPEED_2X16T;                //设置 ADC 工作时钟频率      ADC_SPEED_2X1T~ADC_SPEED_2X16T
      ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED;      //ADC结果调整,      ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
      ADC_Inilize(&ADC_InitStructure);                //初始化
      ADC_PowerControl(ENABLE);                              //ADC电源开关, ENABLE或DISABLE
      NVIC_ADC_Init(DISABLE,Priority_0);                //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
}

/***************串口初始化函数 *****************/
void UART_config(void)
{
      COMx_InitDefine                COMx_InitStructure;                                        //结构定义

      COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;                //模式,   UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
      COMx_InitStructure.UART_BRT_Use   = BRT_Timer1;                        //选择波特率发生器, BRT_Timer1 (注意: 串口2固定使用BRT_Timer2, 所以不用选择)
      COMx_InitStructure.UART_BaudRate= 9600ul;                              //波特率,   110 ~ 115200
      COMx_InitStructure.UART_RxEnable= ENABLE;                              //接收允许,   ENABLE或DISABLE
      UART_Configuration(UART1, &COMx_InitStructure);                        //初始化串口1 USART1,USART2,USART3,USART4
      NVIC_UART1_Init(ENABLE,Priority_1);                                                //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
      UART1_SW(UART1_SW_P30_P31);                                                                //UART1_SW_P30_P31
}


/***************电压采集函数 *****************/
/***************参数:分压比 *****************/
/******************测试完成*********************/
u16      GetVin(u32 rate, u32 adc_value)
{
      u16 vin;
      vin = (VCC * adc_value * rate) >> 10;
      return vin;
}      

/***************温度采集函数 *****************/
/***********参数:R1-平衡电阻值***************/
/*****************测试完成**********************/
u8         GetTemp(u16 adc)
{
      //变量定义
      u16 Rntc;                              //热敏电阻值
      u8 Temp = 0;                        //温度
      
      Rntc = 2048000 / adc - 3000;                //(10位ADC)计算热敏电阻值
      //根据热敏电阻计算温度
      if(Rntc > 14000)
      {
                Temp = 0;
                return Temp;
      }
      else if(Rntc >= 10000)                              //0 - 7
      {
                Temp = 24 - Rntc * 7 / 4000;      
                return Temp;               
      }
      else if(Rntc >= 9000)                              //7 - 9
      {
                Temp = 27 - Rntc / 500;
                return Temp;      
      }
      else if(Rntc >= 8000)                              //9 - 12
      {
                Temp = 36 - Rntc * 3 / 1000;
                return Temp;
      }
      else if(Rntc >= 7000)                              //12 - 15
      {
                Temp = 36 - Rntc * 3 / 1000;
                return Temp;
      }
      else if(Rntc >= 6000)                              //15 - 20
      {
                Temp = 50 - Rntc / 200;
                return Temp;
      }
      else if(Rntc >= 5000)                              //20 - 26
      {
                Temp = 56 - Rntc * 3 / 500;
                return Temp;
      }
      else if(Rntc >= 4000)                              //26 - 32
      {
                Temp = 56 - Rntc * 3 / 500;
                return Temp;
      }
      else if(Rntc >= 3000)                              //32 - 40
      {
                Temp = 64 - Rntc / 125;
                return Temp;
      }
      else if(Rntc >= 2000)                              //40 - 52
      {
                Temp = 76 - Rntc * 3 / 250;
                return Temp;
      }
      else if(Rntc >= 1000)                              //52 - 75
      {
                Temp = 98 - Rntc * 23 / 1000;
                return Temp;
      }
      else if(Rntc >= 900)                                        //75 - 80
      {
                Temp = 125 - Rntc / 20;
                return Temp;
      }
      else if(Rntc >= 800)                                        //80 - 82
      {
                Temp = 98 - Rntc / 50;
                return Temp;
      }
      else if(Rntc >= 700)                                        //82 - 87
      {
                Temp = 122 - Rntc / 20;
                return Temp;               
      }
      else if(Rntc >= 600)                                        //87 - 93
      {
                Temp = 129 - Rntc * 3 / 50;
                return Temp;
      }
      else if(Rntc >= 500)                                        //93 - 100
      {
                Temp = 135 - Rntc * 7 / 100;
                return Temp;
      }
      else if(Rntc >= 400)                                        //100 - 107
      {
                Temp = 135 - Rntc * 7 / 100;
                return Temp;
      }      
      else if(Rntc >= 300)                                        //107 - 120
      {
                Temp = 159 - Rntc * 13 / 100;
                return Temp;
      }
      else if(Rntc >= 190)                                        //120 - 140
      {
                Temp = 174 - Rntc * 2 / 11;
                return Temp;
      }
      else
      {
                Temp = 140;
                return Temp;
      }
}

/**********************************************/

/**********************************************/
/*
      发送报文
*/
u8 Send_UpData(void)
{
      u16 relay = 0;
      
      //发送报文头
      SBUF = 0xEF;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送电压值
      SBUF = pwruartdata.BUSVoltage;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送温度值
      SBUF = pwruartdata.IGBTTemperature;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送错误状态
      SBUF = pwruartdata.Flagbit.all;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送5s内制动时间
      SBUF = pwruartdata.DISCTimes;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送备用字节
      SBUF = 0xFF;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      relay = 0;
      
      //发送校验码
      SBUF = (0xEF + pwruartdata.BUSVoltage + pwruartdata.IGBTTemperature + pwruartdata.Flagbit.all + pwruartdata.DISCTimes + 0xFF) & 0xFF;
      COM1.B_TX_busy = 1;                //标志忙
      while(COM1.B_TX_busy)
      {
                if(++relay > 39999)
                {
                        return 0;
                }
      }
      
      return 1;
}

/**********************************************/

/**********************************************/
/*
      数据采集      
-      电压采集频率:10KHz               
-      温度采集频率:1KHz                        
-      数据获取频率:1KHz
*/
u8 GetVinValue(void)
{
      static u8 cnt = 0;
      static u16 adc = 0;
      static u16 vsum = 0;
      static u16 errcnt = 0;


      
      adc = Get_ADCResult(4);                                                                //获取电压ad值
      
      if(adc == 4096)                                                                              //判断ad值是否合法
      {
                if(++errcnt > 1999)                                                                //连续一秒非法ad值报警
                {
                        pwruartdata.Flagbit.fbit.VoltAcqError = 1;                        //电压采集错误标志置1
                }
                return 0;
      }
      else
      {
                errcnt = 0;
      }
      
      vsum += GetVin(251, adc);                                                      //计算十次电压总和
      if(++cnt > 9)                                                                              //平均滤波
      {
                vcatch = (vsum * 1.05) / cnt;                                        //添加比例增益补偿                2024/9/5
                pwruartdata.BUSVoltage = vcatch / 3;
                cnt = 0;
                vsum = 0;
      }
      
      pwruartdata.Flagbit.fbit.VoltAcqError = 0;
      return 1;
}

u8 GetTempValue(void)
{
      static u16 cnt = 0;
      static u16 adc = 0;
      static u32 tsum = 0;
      static u16 errcnt = 0;


      
      adc = Get_ADCResult(5);                                                                //获取温度ad值
      
      if(adc == 4096)                                                                              //判断ad值是否合法
      {
                if(++errcnt > 999)                                                                //连续一秒非法ad值报警
                {
                        pwruartdata.Flagbit.fbit.TempAcqError = 1;      //温度采集错误标志置1
                }
                return 0;
      }
      else
      {
                errcnt = 0;
      }
      
      tsum += GetTemp(adc);                                                                //计算五百次温度总和
      if(++cnt > 499)                                                                              //平均滤波
      {
                pwruartdata.IGBTTemperature = tsum / cnt;
                cnt = 0;
                tsum = 0;
      }
      
      pwruartdata.Flagbit.fbit.TempAcqError = 0;
      return 1;
}
/**********************************************/

/**********************************************/
/*
      任务分时函数
*/
void TaskDiv(void)
{
      static u8 timer1 = 0,timer2 = 0,timer3 = 0,timer4 = 0;
      div_01ms = 1;
      if(++timer1 > 9)
      {
                timer1 = 0;
                div_1ms = 1;
                if(++timer2 >9)
                {
                        timer2 = 0;
                        div_10ms = 1;
                        if(++timer3 > 9)
                        {
                              timer3 = 0;
                              div_100ms = 1;
                              if(++timer4 > 9)
                              {
                                        timer4 = 0;
                                        div_1s = 1;
                              }
                        }
                }
      }
}

/**********************************************/

void main(void)
{

      EAXSFR();                /* 扩展寄存器访问使能 */
      GPIO_config();
      UART_config();
      ADC_config();
      TIMER0_config();
      EA = 1;
      
      
      pwruartdata.IGBTTemperature = 0;
      pwruartdata.BUSVoltage = 0;
      pwruartdata.Flagbit.all = 0;
      //轮询
      while (1)////////////////////////
      {
               
                if(div_01ms)                                                //0.1ms任务
                {
                        GetVinValue();
                        div_01ms = 0;
                }
                if(div_1ms)                                                      //1ms任务
                {
                        GetTempValue();
                        div_1ms = 0;
                }
                if(div_10ms)                                                //10ms任务
                {
                        Send_UpData();
                        div_10ms = 0;
                }
               
                if(div_100ms)                                                //100ms任务
                {
                        div_100ms = 0;
                }
               
                if(div_1s)                                                      //1s任务
                {
                        div_1s = 0;
                }
      }
}


其他有什么需要了解的都可以问我

VCC 发表于 2024-11-7 16:31:05

看起来是 Get_ADCResult 函数返回了4096?不是12位ADC吗,数值范围应该是0~4095。

Emmetttttt 发表于 2024-11-7 16:37:33

VCC 发表于 2024-11-7 16:31
看起来是 Get_ADCResult 函数返回了4096?不是12位ADC吗,数值范围应该是0~4095。

这个芯片是10位ADC,那个函数是官方示例里的,4096只是错误值

晓飛飛 发表于 2024-11-7 21:25:47

发现了好多变量类型使用不规范或者不匹配的情况,C语言各种变量的取值范围要看看啊

Emmetttttt 发表于 2024-11-8 08:24:57

晓飛飛 发表于 2024-11-7 21:25
发现了好多变量类型使用不规范或者不匹配的情况,C语言各种变量的取值范围要看看啊 ...

可能有些范围会更大,但没有出现不够越界的情况

乘风飞扬 发表于 2024-11-18 15:44:50

Get_ADCResult返回4096的情况有2种
1是输入的通道参数超过15
2是ADC采样时间超时
你可以通过这两个方面排查,先确定是通道参数问题还是采样超时问题。

Emmetttttt 发表于 2024-11-18 15:48:30

乘风飞扬 发表于 2024-11-18 15:44
Get_ADCResult返回4096的情况有2种
1是输入的通道参数超过15
2是ADC采样时间超时


之前用过控制寄存器方式采样,就是卡死在ADC采样时间超时了,一直收不到采样成功的标志

乘风飞扬 发表于 2024-11-19 09:03:00

Emmetttttt 发表于 2024-11-18 15:48
之前用过控制寄存器方式采样,就是卡死在ADC采样时间超时了,一直收不到采样成功的标志 ...

确认一下你用的芯片8G1K08后面是带“A”的?如果不带A的8PIN芯片是没有ADC功能的。
确定带“A”的话,可以直接烧录附件例子的hex文件到芯片里试试,串口打印ADC采集结果。

Emmetttttt 发表于 2024-11-22 09:20:13

乘风飞扬 发表于 2024-11-19 09:03
确认一下你用的芯片8G1K08后面是带“A”的?如果不带A的8PIN芯片是没有ADC功能的。
确定带“A”的话,可 ...

接收←ADC00=1023
接收←ADC01=1023
接收←ADC02=0018
接收←ADC03=0034
接收←ADC04=0000
接收←ADC05=0261
接收←ADC06=0000
接收←ADC07=0000
                  
接收←ADC08=0000
接收←ADC09=0000
接收←ADC10=0000
接收←ADC11=0000
接收←ADC12=0000
接收←ADC13=0000
接收←ADC14=0000
接收←Bandgap=0250
这是打印出来的结果

Emmetttttt 发表于 2024-11-22 09:23:02

这是ADC4和5部分的原理图
页: [1] 2
查看完整版本: 关于AI8G1K08A-8Pin的ADC采样问题