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

  • Post author:
  • Post category:其他


   在使用STC8时需要采集多路小电压值,使用LCD1602显示。但是STC8单片机内部只有10和12位精度的ADC,采集毫伏级电压就不够精确。这时可采用外挂高精度ADC实现。常见的有ADS1115、ADS1256、MCP3421以及国产的TM7705等。本方案采用STC8单片机与ADC1256实现多路AD采集。
    ADS1256是一款低噪声高分辨率的24位ADC,ADS1256数据输出速率最高可为30K采样点/秒(SPS),4路差分与8路单端输入,SPI接口。原理图如下所示:
    ![ADS1256](https://img-blog.csdnimg.cn/20210714142524264.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NDA2NDI1,size_16,color_FFFFFF,t_70#pic_center)## 电路连接
    使用现成的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头文件:

// QQ:2401553359     QQ群:560864628
#ifndef __ADS1256_H_
#define	__ADS1256_H_


// define commands 
#define ADS1256_CMD_WAKEUP   0x00 
#define ADS1256_CMD_RDATA    0x01 
#define ADS1256_CMD_RDATAC   0x03 
#define ADS1256_CMD_SDATAC   0x0f 
#define ADS1256_CMD_RREG     0x10 
#define ADS1256_CMD_WREG     0x50 
#define ADS1256_CMD_SELFCAL  0xf0 
#define ADS1256_CMD_SELFOCAL 0xf1 
#define ADS1256_CMD_SELFGCAL 0xf2 
#define ADS1256_CMD_SYSOCAL  0xf3 
#define ADS1256_CMD_SYSGCAL  0xf4 
#define ADS1256_CMD_SYNC     0xfc 
#define ADS1256_CMD_STANDBY  0xfd 
#define ADS1256_CMD_REST    0xfe 
 
// define the ADS1256 register values 
#define ADS1256_STATUS       0x00   
#define ADS1256_MUX          0x01   
#define ADS1256_ADCON        0x02   
#define ADS1256_DRATE        0x03   
#define ADS1256_IO           0x04   
#define ADS1256_OFC0         0x05   
#define ADS1256_OFC1         0x06   
#define ADS1256_OFC2         0x07   
#define ADS1256_FSC0         0x08   
#define ADS1256_FSC1         0x09   
#define ADS1256_FSC2         0x0A 
 
 
// define multiplexer codes 
#define ADS1256_MUXP_AIN0   0x00 
#define ADS1256_MUXP_AIN1   0x10 
#define ADS1256_MUXP_AIN2   0x20 
#define ADS1256_MUXP_AIN3   0x30 
#define ADS1256_MUXP_AIN4   0x40 
#define ADS1256_MUXP_AIN5   0x50 
#define ADS1256_MUXP_AIN6   0x60 
#define ADS1256_MUXP_AIN7   0x70 
#define ADS1256_MUXP_AINCOM 0x80 
 
#define ADS1256_MUXN_AIN0   0x00 
#define ADS1256_MUXN_AIN1   0x01 
#define ADS1256_MUXN_AIN2   0x02 
#define ADS1256_MUXN_AIN3   0x03 
#define ADS1256_MUXN_AIN4   0x04 
#define ADS1256_MUXN_AIN5   0x05 
#define ADS1256_MUXN_AIN6   0x06 
#define ADS1256_MUXN_AIN7   0x07 
#define ADS1256_MUXN_AINCOM 0x08   
 
 
// define gain codes 
#define ADS1256_GAIN_1      0x00 
#define ADS1256_GAIN_2      0x01 
#define ADS1256_GAIN_4      0x02 
#define ADS1256_GAIN_8      0x03 
#define ADS1256_GAIN_16     0x04 
#define ADS1256_GAIN_32     0x05 
#define ADS1256_GAIN_64     0x06 
//#define ADS1256_GAIN_64     0x07 
 
//define drate codes 
#define ADS1256_DRATE_30000SPS   0xF0 
#define ADS1256_DRATE_15000SPS   0xE0 
#define ADS1256_DRATE_7500SPS   0xD0 
#define ADS1256_DRATE_3750SPS   0xC0 
#define ADS1256_DRATE_2000SPS   0xB0 
#define ADS1256_DRATE_1000SPS   0xA1 
#define ADS1256_DRATE_500SPS    0x92 
#define ADS1256_DRATE_100SPS    0x82 
#define ADS1256_DRATE_60SPS     0x72 
#define ADS1256_DRATE_50SPS     0x63 
#define ADS1256_DRATE_30SPS     0x53 
#define ADS1256_DRATE_25SPS     0x43 
#define ADS1256_DRATE_15SPS     0x33 
#define ADS1256_DRATE_10SPS     0x23 
#define ADS1256_DRATE_5SPS      0x13 
#define ADS1256_DRATE_2_5SPS    0x03

signed long ADS1256ReadData(unsigned char channel);
void ADS1256_Init(void);   //初始化ADS1256
void Init_ADS1256_GPIO(void); //

#endif

对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;
}

初始化LCD1602显示,这里定义的是8线并行接口,可以修改为4线串行接口:

sbit LCD_EN=P1^0;  //STC8G1K08——20Pin
sbit LCD_RW=P1^1;
sbit LCD_RS=P1^7;

#define LINE1_COLUMN(x) 0x7f+x
#define LINE2_COLUMN(x) 0xbf+x

#define LCD_DATAPORT P3//端口可改,模式可以改成串行的,减小引脚使用

void DelayMs( u16 ms)//延时
{
	u16 i,j;
	for (i = 0; i < ms; i++)
		for(j=0;j<115;j++);
}

void delay_ms(u16 nms)
{
	u16 x,y;
	for(x=nms;x>0;x--)
		for(y=120;y>0;y--);
}

void LCD1602_WriteCMD(u8 cmd)//LCD1602写命令函数
{
	 LCD_RS=0;
	 LCD_DATAPORT=cmd;
	 delay_ms(1);
	 LCD_EN=1;
	 delay_ms(1);
	 LCD_EN=0;
}

void LCD1602_WriteData(u8 dat)//LCD1602写数据函数
{
	 LCD_RS=1;
	 LCD_DATAPORT=dat;
	 delay_ms(1);
	 LCD_EN=1;
	 delay_ms(1);
	 LCD_EN=0;
}

void display_char(u8 addr,u8 chr)
{
	LCD1602_WriteCMD(addr);
	LCD1602_WriteData(chr);
}

void display_num4(u8 addr,u16 num)//显示
{
	u8 qian,bai,shi,ge;
	qian= num/1000;
	bai = num/100%10;
	shi = num/10%10;
	ge = num%10;			//变量分离
	display_char(addr,qian+'0');//保留两位小数,
	display_char(addr+1,bai+'0');
	display_char(addr+2,'.');
	display_char(addr+3,shi+'0');
	display_char(addr+4,ge+'0');
	display_char(LINE1_COLUMN(1),'V');//第一行写字符,VIN:、V、A
	display_char(LINE1_COLUMN(2),'I');
	display_char(LINE1_COLUMN(3),'N');
	display_char(LINE1_COLUMN(4),':');
	display_char(LINE1_COLUMN(10),'V');
	display_char(LINE1_COLUMN(16),'A');
	display_char(LINE2_COLUMN(1),'O');//第二行写字符,OUT:、V、A
	display_char(LINE2_COLUMN(2),'U');
	display_char(LINE2_COLUMN(3),'T');
	display_char(LINE2_COLUMN(4),':');
	display_char(LINE2_COLUMN(10),'V');
	display_char(LINE2_COLUMN(16),'A');
}

void LCD_Init(void)
{
	
	LCD_EN=0;//打开片选
	LCD_RW=0;//读写控制,1:读	
	//			 0:写	 这里只写,不读
	LCD1602_WriteCMD(0x38);
	LCD1602_WriteCMD(0x0e);
	LCD1602_WriteCMD(0x06);//地址指针自动加一,且光标加一
	LCD1602_WriteCMD(0x01);
	LCD1602_WriteCMD(0x80);
}

编写主函数,这里测量单端电压,如果需要测量差分电压的话按照上面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



版权声明:本文为qq_44406425原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。