打印
[STC单片机]

STC8单片机驱动ADS1256多路AD采集

[复制链接]
5170|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
何程|  楼主 | 2021-7-15 10:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
        在使用STC8时需要采集多路小电压值,使用LCD1602显示。但是STC8单片机内部只有10和12位精度的ADC,采集毫伏级电压就不够精确。这时可采用外挂高精度ADC实现。常见的有ADS1115、ADS1256、MCP3421以及国产的TM7705等。本方案采用STC8单片机与ADC1256实现多路AD采集。

        ADS1256是一款低噪声高分辨率的24位ADC,ADS1256数据输出速率最高可为30K采样点/秒(SPS),4路差分与8路单端输入,SPI接口。

      使用现成的ADS1256模块,制作一个STC8G1K08单片机最小系统(可以改成STC8H8K64U、STC8A8K64S4A12或者STC8G2K64),在程序中直接定义SPI通信接口以及LCD1602显示接口,相关定义如下:

        //SPI通信接口
   sbit SCK  = P1^2;
        sbit DIN  = P1^3;
        sbit DOUT = P1^4;
        sbit DRDY = P1^5;
        sbit CS   = P1^6;
//LCD1602引脚接口
sbit LCD_EN=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_RS=P1^7;

#define LCD_DATAPORT P3
对ADS1256初始化:包括SPI通信初始化,读取AD值等。

// QQ:2401553359     QQ群:560864628
#include "STC8.H"
#include "ADS1256.h"
        /*端口定义*/

        sbit SCK  = P1^2;
        sbit DIN  = P1^3;
        sbit DOUT = P1^4;
        sbit DRDY = P1^5;
        sbit CS   = P1^6;

        #define CS_0()                CS = 0
        #define CS_1()                CS = 1
        #define SCK_0()                SCK = 0
        #define SCK_1()                SCK = 1

        #define ADS1256_DIN_0()        DIN = 0
        #define ADS1256_DIN_1()        DIN = 1

        #define ADS1256_DRDY   DRDY
        #define ADS1256_DOUT   DOUT

void delay_ms(u16);

//void Init_ADS1256_GPIO(void)
//{
//        /********************************************
//                 提示:写单片机程序配置I/O口时要注意方向,
//                I/O口配置输出时推荐配置为推挽模式,有些老
//                的51单片机没有推挽模式,推荐加 1K上拉电阻.
//         ********************************************/
//        P1M1 =0x00;
//        P1M0 =0xff; //配置 I O
//        CS_1();
//}



static void ADS1256_DelaySCLK(void)
{
        unsigned short i;

        /*
                取 5 时,实测高电平200ns, 低电平250ns <-- 不稳定
                取 10 以上,可以正常工作, 低电平400ns 高定400ns <--- 稳定
        */
        for (i = 0; i < 20; i++);
}
/*
*********************************************************************************************************
*        函 数 名: SPI_WriteByte
*        功能说明: 向SPI总线发送8个bit数据。 不带CS控制。
*        形    参: _data : 数据
*        返 回 值: 无
*********************************************************************************************************
*/
void SPI_WriteByte(unsigned char TxData)
{
        unsigned char i;
        /* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
        for(i = 0; i < 8; i++)
        {
                if (TxData & 0x80)
                        ADS1256_DIN_1();
                else
                        ADS1256_DIN_0();
               
                SCK_1();
                //ADS1256_DelaySCLK();
                TxData <<= 1;
                SCK_0();                        /* <----  ADS1256 是在SCK下降沿采样DIN数据, 数据必须维持 50nS */
                //ADS1256_DelaySCLK();
        }
       
}

/*
*********************************************************************************************************
*        函 数 名: SPI_ReadByte
*        功能说明: 从SPI总线接收8个bit数据。 不带CS控制。
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
unsigned char SPI_ReadByte(void)
{
        unsigned char i;
        unsigned char read = 0;

        //ADS1256_DelaySCLK();

        /* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
        for (i = 0; i < 8; i++)
        {
                SCK_1();
                ADS1256_DelaySCLK();
                read = read<<1;
                SCK_0();
                if (ADS1256_DOUT)
                {
                        read++;
                }
                ADS1256_DelaySCLK();
        }
        return read;
}

//-----------------------------------------------------------------//
//        功    能:ADS1256 写数据
//        入口参数: /
//        出口参数: /
//        全局变量: /
//        备    注: 向ADS1256中地址为regaddr的寄存器写入一个字节databyte
//-----------------------------------------------------------------//
void ADS1256WREG(unsigned char regaddr,unsigned char databyte)
{
   
        CS_0();
        while(ADS1256_DRDY);//当ADS1256_DRDY为低时才能写寄存器
        //向寄存器写入数据地址
    SPI_WriteByte(ADS1256_CMD_WREG | (regaddr & 0x0F));
    //写入数据的个数n-1
    SPI_WriteByte(0x00);
    //向regaddr地址指向的寄存器写入数据databyte
    SPI_WriteByte(databyte);
        CS_1();
}


//初始化ADS1256
void ADS1256_Init(void)
{

        //*************自校准****************
   while(ADS1256_DRDY);
        CS_0();
        SPI_WriteByte(ADS1256_CMD_SELFCAL);
        while(ADS1256_DRDY);
        CS_1();
        //**********************************

        ADS1256WREG(ADS1256_STATUS,0x06);               // 高位在前、校准、使用缓冲
//        ADS1256WREG(ADS1256_STATUS,0x04);               // 高位在前、不使用缓冲
//        ADS1256WREG(ADS1256_MUX,0x08);                  // 初始化端口A0为‘+’,AINCOM位‘-’
        ADS1256WREG(ADS1256_ADCON,ADS1256_GAIN_1);      // 放大倍数1
        ADS1256WREG(ADS1256_DRATE,ADS1256_DRATE_10SPS); // 数据5sps
        ADS1256WREG(ADS1256_IO,0x00);  
                     
        //*************自校准****************
        while(ADS1256_DRDY);
        CS_0();
        SPI_WriteByte(ADS1256_CMD_SELFCAL);
        while(ADS1256_DRDY);
        CS_1();
        //**********************************

}


//读取AD值
signed long ADS1256ReadData(unsigned char channel)  
{
  signed long sum=0;
        char i;
        unsigned long r=0;
       
        while(ADS1256_DRDY);//当ADS1256_DRDY为低时才能写寄存器
        ADS1256WREG(ADS1256_MUX,channel);                //设置通道
        CS_0();
        SPI_WriteByte(ADS1256_CMD_SYNC);//外同步AD信号,启动转换
        SPI_WriteByte(ADS1256_CMD_WAKEUP);//完成同步并退出待机模式          
        while(ADS1256_DRDY);       
        SPI_WriteByte(ADS1256_CMD_RDATA);
        delay_ms(1);
       
        for(i=0;i<3;i++)
    {
            sum = sum << 8;
                r = SPI_ReadByte();  
                  sum |= r;
        }       

        CS_1();

        if (sum>0x7FFFFF)           // if MSB=1,
        {
                sum -= 0x1000000;       // do 2's complement
        }

    return sum;
}
编写主函数,这里测量单端电压,如果需要测量差分电压的话按照上面ADS1256头文件修改一下就行了。
void main()//ADS126的PGA不是轨到轨运放,采集3.6V以内电压比较好
{             //如果超过,须加分压电路
        signed        long Adc;//QQ:2401553359,QQ群:560864628
        float  Volts;
        P1M0=0X00;P1M1=0X00;//配置GPIO模式,建议用准双向或者推挽模式
  P3M0=0X00;P3M1=0X00;
  ADS1256_Init();                        //ADS1256 参数初始化
        LCD_Init();
        while(1)//系数自己用基准电压源校准,电赛那时改动太多了。
        {
                Adc = ADS1256ReadData( ADS1256_MUXP_AIN0|ADS1256_MUXN_AINCOM);       
                Volts = (Adc*0.00059270)*0.2010; // 0.00000059263 为系数,ADC生产出后都有一定的偏差,在此校准。
                display_num4(LINE1_COLUMN(5),Volts);
                delay_ms(50);
               
                Adc = ADS1256ReadData( ADS1256_MUXP_AIN1|ADS1256_MUXN_AINCOM);       
                Volts = (Adc*0.00059270)*0.915; // 0.00000059263 为系数,ADC生产出后都有一定的偏差,在此校准。
                display_num4(LINE1_COLUMN(11),Volts);
                delay_ms(50);
               
                Adc = ADS1256ReadData( ADS1256_MUXP_AIN2|ADS1256_MUXN_AINCOM);       
                Volts = (Adc*0.00058136)*1.910; // 0.00000059263 为系数,ADC生产出后都有一定的偏差,在此校准。
                display_num4(LINE2_COLUMN(5),Volts);
                delay_ms(50);
               
          Adc = ADS1256ReadData( ADS1256_MUXP_AIN3|ADS1256_MUXN_AINCOM);       
                Volts = (Adc*0.00059270)*0.6015; // 0.00000059263 为系数,ADC生产出后都有一定的偏差,在此校准。
                display_num4(LINE2_COLUMN(11),Volts);
                DelayMs(50);
        }
}
LCD1602显示效果如下,因为是做电子设计竞赛的,模块比较多,忽略其它模块。

视频链接:https://www.bilibili.com/video/BV1fA41177Um

源码链接:https://pan.baidu.com/s/1dbJw8ggp9Lcxch8wAfIJ4Q

提取码:lm15









使用特权

评论回复

相关帖子

沙发
ahui1105| | 2021-7-16 14:20 | 只看该作者
换锦锐CA51F003T3

使用特权

评论回复
评论
何程 2021-7-16 22:40 回复TA
还没用过,程序兼容STC的吗? 
板凳
Mentalin| | 2022-3-26 12:57 | 只看该作者
大佬呀,STC8 与 ADS1256 直接连接无法读取电压数据,这两个之间需要加什么转换电路吗?

使用特权

评论回复
地板
何程|  楼主 | 2022-4-2 13:45 | 只看该作者
Mentalin 发表于 2022-3-26 12:57
大佬呀,STC8 与 ADS1256 直接连接无法读取电压数据,这两个之间需要加什么转换电路吗? ...

不用加,看看时钟频率对不对

使用特权

评论回复
5
单模先声| | 2022-4-6 16:19 | 只看该作者

锦锐有硬件乘法器吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

44

帖子

1

粉丝