在使用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
|