基于51单片机的差分双路电压检测(基于ADC0832)

news2024/7/6 19:47:02

文章目录

  • 前言
  • 一、本文任务
  • 二、材料
  • 三、电路图
  • 四、代码解读
    • 1.引脚定义及参数
    • 2.定时器中断与延时开启
    • 3.数码管显示定义及ADC0832函数初始化
    • 4.数据转换及数码管显示
    • 5.主函数及定时器函数
    • 6.所有代码(就一个c文件)
  • 总结


前言

博主终于又空出时间啦,积攒了一大波的项目,今天分享一个51单片机利用ADC0832电压检测芯片检测双路差分电压信号的代码+电路图,实测有效!


一、本文任务

根据实际应用情况,可将差分电压衰减N倍以后送入单片机内部进行检测。通过ADC0832芯片将通道0的电压转换成0-255等级,分别对应0-5V,从而实现差分电压的测量。在此过程中,还通过数码管对电压进行显示。

二、材料

1、OPA2188(用作前端电压跟随,此处LM358实测效果不太行,建议更换这个芯片)

2、OPA2188(用作同相放大电路运算芯片,与前者一样,都是一样的芯片)

3、51单片机(AT,STC都可)

4、ADC0832(由于51单片机内部没有ADC芯片,因此需要用到外置的ADC芯片,这个芯片有两个电压检测脚,在代码里面通过设定通道从而检测对应通道的电压)

5、共阴数码管(此处是三位共阴数码管,通过G1-G4进行数码管的片选,别看图里面就一个数码管,其实有三个)

三、电路图

代码如下(示例):
在这里插入图片描述
电路图无需赘述,就是51单片机最小系统板加上一系列的外设,注意的是两个LM358芯片都要用OPA2188芯片来代替,贵是贵了点,架不住效果好哇哈哈哈!

四、代码解读

1.引脚定义及参数

#include <reg51.h>
#include <intrins.h>
/*********************************端口定义**********************************/
sbit CS   = P3^2;           //芯片CS口
sbit Clk = P3^0;            //芯片脉冲输出口
sbit DATI = P3^1;           //data数据通用口
sbit DATO = P3^1;
sbit led=P1^0;	            //定义P20口是输出口
sbit DIAN = P0^5;        		//小数点
/*******************************定义全局变量********************************/
unsigned char dat = 0x00;      //AD值
unsigned char count = 0x00;      //定时器计数
unsigned char CH;       //通道变量
unsigned char dis[4];       //显示数值
unsigned int sum=0;
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

CS/CLK/DATI/DAT0都是ADC0832的输出引脚,要注意的是P31引脚不仅仅用作输出,而且还用作输入,是一个双向的引脚。

led这里解释一下,这个是后面外加的一个功能,主要就是每经过5min检测一次当前差分电位,如果大于某个特定的电压值,就为高电平,小于某个特定的电压值,就为低电平,去掉不影响

DIAN是小数点为,人为设置的

其它均有注释

2.定时器中断与延时开启

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay_ms(u16 i)
{
	while(i--);	
}
/*******************************************************************************
* 函 数 名         : Timer0Init
* 函数功能		   : 定时器0初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0Init()
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

	TH0=0X3C;	//给定时器赋初值,定时50ms
	TL0=0XB0;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器			
}

作用为调用ms级别的延时以及开启定时器0,定时器0的定时时长为50ms,主要是配合LED进行定时的判断输出高低电平。

3.数码管显示定义及ADC0832函数初始化

/*******************************共阴LED段码表*******************************/

unsigned char code tab[]={0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7};
/****************************************************************************
函数功能:AD转换子程序
入口参数:CH
出口参数:dat
****************************************************************************/
unsigned char adc0832(unsigned char CH)
{
	unsigned char i,test,adval;
	adval = 0x00;
	test = 0x00;
	Clk = 0;       //初始化
	DATI = 1;
	_nop_();
	CS = 0;
	_nop_();
	Clk = 1;
	_nop_();
	
	if ( CH == 0x00 )      //通道选择
	{
		Clk = 0;
		DATI = 1;      //通道0的第一位
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
		DATI = 0;      //通道0的第二位
		_nop_();
		Clk = 1;
		_nop_();
	} 
	else
	{
		Clk = 0;
		DATI = 1;      //通道1的第一位
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
		DATI = 1;      //通道1的第二位
		_nop_();
		Clk = 1;
		_nop_();
	}
	
	Clk = 0;
	DATI = 1;
	for( i = 0;i < 8;i++ )      //读取前8位的值
	{
		_nop_();
		adval <<= 1;
		Clk = 1;
		_nop_();
		Clk = 0;
		if (DATO)
		adval |= 0x01;
		else
		adval |= 0x00;
	}
	for (i = 0; i < 8; i++)      //读取后8位的值
	{
		test >>= 1;
		if (DATO)
		test |= 0x80;
		else 
		test |= 0x00;
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
	}
	if (adval == test)      //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
	dat = test;
	nop_();
	CS = 1;        //释放ADC0832
	DATO = 1;
	Clk = 1;
	return dat;
}

会用就行,具体就是通过调用这个函数可以返回0-255的数值,分别对应0-5V,相当于一个8位的数据格式。需要设置的就是CH通道,有两种,一个是0通道,一个是1通道。分别对应ADC0832上面的CH0和CH1,根据自己的需求选择不同通道即可。

4.数据转换及数码管显示

/****************************************************************************
函数功能:延时子程序
入口参数:
出口参数:
****************************************************************************/
void delay(void)
{
    int k;
    for(k=10;k<5000;k++);
}
/****************************************************************************
函数功能:将0-255级换算成0.00-5.00的电压数值
入口参数:i
出口参数:
****************************************************************************/
void convdata(unsigned int i)
{
	i=i*1.96;	 
    dis[0] = i/100;         //个位
    dis[1] = i%100/10;      //小数点后第一位	 
    dis[2] = i%100%10;      //小数点后第二位
//	dis[3] = i%1000%100%10;     
}
/****************************************************************************
函数功能:数码管显示子程序
入口参数:
出口参数:
****************************************************************************/
void display(void)
{  
    P0=tab[dis[0]];      //显示个位和小数点11011111
	DIAN=1;
    P2=0xdf;                  //11011111
    delay_ms(100);    
    P2=0xff;

    P0=tab[dis[1]];       //显示小数点后第一位
    P2=0xbf;                //10111111
    delay_ms(100);
    P2=0xff;

    P0=tab[dis[2]];       //显示小数点后第二位
    P2=0x7f;              //01111111  
    delay_ms(100);
    P2=0xff;
}

convdat函数的逻辑就是将0-255的数值转换成0-500的数值,有个对应关系就是乘以1.96。做这个的主要目的就是为了把从ADC0832上面检测到的8位值转换成0-500的电压表示,500就代表5V,0就代表0V。并且将电压值表现出来。

display函数主要目的就是为了把数据显示到数码管上。逻辑也很简单,P0是控制数码管的显示的,P2口是控制选择哪个数码管的。根据逻辑指令。第一个数据要加上小数点,所以定义了DIAN=1;同时P0口显示当前的数字,这个是直接调用的tab数组,在最开始的参数定义里面已经定义好了共阴数码管所对应的数字数组。同时P2口设置为0xdf,我也在注释那里用二进制表现出来了,其实就是对应的数码管。

5.主函数及定时器函数

/****************************************************************************
函数功能:主程序
入口参数:
出口参数:
****************************************************************************/
void main(void)
{
	unsigned char m;   
	CH = 0x00;       //在这里选择通道 0x00或0x01
	Timer0Init();    //定时器0初始化
	while(1)         //主循环		  
	{
		for(m=0;m<50;m++) //检测50次取平均提高检测精度
		{
			dat = adc0832(CH);
			sum=sum+dat;
		}
		dat=sum/50;
		sum=0; 
		convdata(dat);  //数据转换
		display();      //显示数值
	}
}

/*******************************************************************************
* 函 数 名         : void Timer0() interrupt 1
* 函数功能		   : 定时器0中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0() interrupt 1
{
	static u16 i;
	TH0=0X3C;	//给定时器赋初值,定时50ms
	TL0=0XB0;
	i++;
	if(i==6000)//如果过了5分钟,检测一次输出高低电位
	{
		if(dat>=153)
		led=0;
    else
    led=1;			
	}	
	if(i==6200)//再过10s,输出强制为0
	{
		i=0;
		led=0;
	}
}

主函数里面设置了通道0的检测。同时开启了定时器0的初始化。在while循环里面,对通道0的电压进行了50次的检测,并且将50次的检测出来的数据累加最后取50次的平均,平均后的数据再进行格式的转换以及数码管的显示。在定时器里面每隔5min进行一次电压的判断,前文提到过。

6.所有代码(就一个c文件)

#include <reg51.h>
#include <intrins.h>
/*********************************端口定义**********************************/
sbit CS   = P3^2;           //芯片CS口
sbit Clk = P3^0;            //芯片脉冲输出口
sbit DATI = P3^1;           //data数据通用口
sbit DATO = P3^1;
sbit led=P1^0;	            //定义P20口是输出口
sbit DIAN = P0^5;        		//小数点
/*******************************定义全局变量********************************/
unsigned char dat = 0x00;      //AD值
unsigned char count = 0x00;      //定时器计数
unsigned char CH;       //通道变量
unsigned char dis[4];       //显示数值
unsigned int sum=0;
typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;
/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay_ms(u16 i)
{
	while(i--);	
}
/*******************************************************************************
* 函 数 名         : Timer0Init
* 函数功能		   : 定时器0初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0Init()
{
	TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。

	TH0=0X3C;	//给定时器赋初值,定时50ms
	TL0=0XB0;	
	ET0=1;//打开定时器0中断允许
	EA=1;//打开总中断
	TR0=1;//打开定时器			
}
/*******************************共阴LED段码表*******************************/

unsigned char code tab[]={0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7};
/****************************************************************************
函数功能:AD转换子程序
入口参数:CH
出口参数:dat
****************************************************************************/
unsigned char adc0832(unsigned char CH)
{
	unsigned char i,test,adval;
	adval = 0x00;
	test = 0x00;
	Clk = 0;       //初始化
	DATI = 1;
	_nop_();
	CS = 0;
	_nop_();
	Clk = 1;
	_nop_();
	
	if ( CH == 0x00 )      //通道选择
	{
		Clk = 0;
		DATI = 1;      //通道0的第一位
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
		DATI = 0;      //通道0的第二位
		_nop_();
		Clk = 1;
		_nop_();
	} 
	else
	{
		Clk = 0;
		DATI = 1;      //通道1的第一位
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
		DATI = 1;      //通道1的第二位
		_nop_();
		Clk = 1;
		_nop_();
	}
	
	Clk = 0;
	DATI = 1;
	for( i = 0;i < 8;i++ )      //读取前8位的值
	{
		_nop_();
		adval <<= 1;
		Clk = 1;
		_nop_();
		Clk = 0;
		if (DATO)
		adval |= 0x01;
		else
		adval |= 0x00;
	}
	for (i = 0; i < 8; i++)      //读取后8位的值
	{
		test >>= 1;
		if (DATO)
		test |= 0x80;
		else 
		test |= 0x00;
		_nop_();
		Clk = 1;
		_nop_();
		Clk = 0;
	}
	if (adval == test)      //比较前8位与后8位的值,如果不相同舍去。若一直出现显示为零,请将该行去掉
	dat = test;
	nop_();
	CS = 1;        //释放ADC0832
	DATO = 1;
	Clk = 1;
	return dat;
}
/****************************************************************************
函数功能:延时子程序
入口参数:
出口参数:
****************************************************************************/
void delay(void)
{
    int k;
    for(k=10;k<5000;k++);
}
/****************************************************************************
函数功能:将0-255级换算成0.00-5.00的电压数值
入口参数:i
出口参数:
****************************************************************************/
void convdata(unsigned int i)
{
	i=i*1.96;	 
    dis[0] = i/100;         //个位
    dis[1] = i%100/10;      //小数点后第一位	 
    dis[2] = i%100%10;      //小数点后第二位
//	dis[3] = i%1000%100%10;     
}
/****************************************************************************
函数功能:数码管显示子程序
入口参数:
出口参数:
****************************************************************************/
void display(void)
{  
    P0=tab[dis[0]];      //显示个位和小数点11011111
	DIAN=1;
    P2=0xdf;                  //11011111
    delay_ms(100);    
    P2=0xff;

    P0=tab[dis[1]];       //显示小数点后第一位
    P2=0xbf;                //10111111
    delay_ms(100);
    P2=0xff;

    P0=tab[dis[2]];       //显示小数点后第二位
    P2=0x7f;              //01111111  
    delay_ms(100);
    P2=0xff;
}
/****************************************************************************
函数功能:主程序
入口参数:
出口参数:
****************************************************************************/
void main(void)
{
	unsigned char m;   
	CH = 0x00;       //在这里选择通道 0x00或0x01
	Timer0Init();    //定时器0初始化
	while(1)         //主循环		  
	{
		for(m=0;m<50;m++) //检测50次取平均提高检测精度
		{
			dat = adc0832(CH);
			sum=sum+dat;
		}
		dat=sum/50;
		sum=0; 
		convdata(dat);  //数据转换
		display();      //显示数值
	}
}

/*******************************************************************************
* 函 数 名         : void Timer0() interrupt 1
* 函数功能		   : 定时器0中断函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0() interrupt 1
{
	static u16 i;
	TH0=0X3C;	//给定时器赋初值,定时50ms
	TL0=0XB0;
	i++;
	if(i==6000)//如果过了5分钟,检测一次输出高低电位
	{
		if(dat>=153)
		led=0;
    else
    led=1;			
	}	
	if(i==6200)//再过10s,输出强制为0
	{
		i=0;
		led=0;
	}
}

总结

点赞收藏评论三连哦,你们的支持就是我最大的动力哈哈哈,坚持分享!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/463235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二战失利,剩下的路?

作者&#xff1a;阿秀 校招八股文学习网站&#xff1a;https://interviewguide.cn 这是阿秀的第「260」篇原创 小伙伴们大家好&#xff0c;我是阿秀。 欢迎今年参加秋招的小伙伴加入阿秀的学习圈&#xff0c;目前已经超过 2300 小伙伴加入&#xff01;去年认真准备和走下来的基…

如何使用chatGPT生成小红书种草文案

如何使用chatGPT生成小红书种草文案 小红书拥有超千万的日活用户&#xff0c;为商家提供了广阔的变现空间和机会&#xff0c;成为商家选择在小红书上推广的原因之一。 小红书种草文案&#xff0c;例如具有影响力的热门话题、产品使用方法等内容可以让消费者迅速了解产品为品牌…

小米青春版路由器刷openwrt

下载小米路由器R1CL开发版 通过手动上传更新&#xff0c;更改固件版本 将之前地址栏URL中的 /web/home#router 替换为&#xff08;密码为admin&#xff09; /api/xqsystem/set_name_password?oldPwd123456789&newPwdadmin如果网页返回 {“code”:0} &#xff0c;则说明修…

JAVA的BIO、NIO、AIO模式精解(一)

1. BIO、NIO、AIO介绍 在不同系统或进程间数据交互&#xff0c;或高并发场景下都选哟网络通信。早期是基于性能低下的同步阻塞IO(BIO)实现。后支持非阻塞IO(NIO)。 前置须知&#xff1a;javsse&#xff0c;java多线程&#xff0c;javaIO&#xff0c;java网络模型 目的&#xf…

[江西专升本/信息技术]计算机网络基础

1、概论 目前主要从资源共享观点定义计算机网络&#xff1a; 用通信路线和通信设备将分布在不同地点的具有独立功能的多个计算机系统相互连接起来&#xff0c;在功能完善的网络软件的支持下实现彼此之间的数据通信和资源共享的系统&#xff1b; 我们可以这么说&#xff0c;“…

effective c++ item30-34

item30:理解inline 1、inline函数 用inline修饰函数可以防止multiple definition的错误 // foo.h inline int foo(int x){ // 如果不加inline&#xff0c;在编译时会有两个foo.h被包含进去&#xff0c;导致链接出错static int n 1;return x * (n ); } // bar1.cpp #includ…

【车道线算法】GANet-车道线检测环境配置一文通关

目录 GANet配置全纪录 下载代码 conda环境部署 安装torch和cudatoolkit 安装其他包 编译 总结 GANet配置全纪录 下载代码 GitHub - Wolfwjs/GANet: A Keypoint-based Global Association Network for Lane Detection. Accepted by CVPR 2022 进入代码网址的默认master…

ArcGIS Pro工程

目录 1 工程基础架构 2 工程内容 3 新建工程及工程文件 3.1 工程模板 3.2 工程名称和位置 3.2.1 基于“地图模板”创建新工程 3.2.2 基于“目录模板”创建新工程 3.2.3 基于“全局场景”创建新工程 3.2.4 基于“局部场景”创建新工程 3.3 工程文件 3.3.1 默认地理…

子元素选择器

知识点&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" c…

【MySQL高级】——用户与权限管理

一、用户管理 <1> 登录 mysql –h hostname|hostIP –P port –u username –p DatabaseName –e "SQL语句"-h参数 后面接主机名或者主机IP&#xff0c;hostname为主机&#xff0c;hostIP为主机IP。 -P参数 后面接MySQL服务的端口&#xff0c;通过该参数连接…

序列检测和序列发生器——verilog代码实现

文章目录 前言一、序列检测器1.1 重复序列检测1.1.1 序列缓存对比/移位寄存器法1.1.2 状态机法 1.2 非重复序列检测 二、序列发生器2.1 移位寄存器法2.2 反馈法2.3 计数器法 前言 2023.4.25 2023.4.26 学习打卡&#xff0c;天气转晴 一、序列检测器 1.1 重复序列检测 1.1.1 …

HTML基础标签

目录 1.html文件结构 2.注释 3.文本标签 4.图片 5.音频与视频 6.超链接 7.表单 8.列表&#xff08;可以嵌套&#xff09; 无序列表 有序列表 定义列表 9.表格 10.语义标签 11.特殊符号 1.html文件结构 <!-- 文档类型声明 --> <!DOCTYPE html> <html>…

学系统集成项目管理工程师(中项)系列12_干系人管理

1. 要管理干系人的期望&#xff0c;更要保证他们的适度参与&#xff0c;而后者是项目成功非常关键的因素之一 1.1. 识别干系人及其信息 1.2. 评估关键干系人的诉求和影响力 1.3. 对干系人分类 1.4. 制定干系人管理计划 1.5. 【19上选56】 2. 识别干系人 2.1. 典型干系人…

如何解决宝塔面板nginx占用80端口的问题

前言: 由于使用Docker部署前端项目老是报错说80端口被占用,所以不得不去查找原因并且解决 上网查了很多资料说修改80端口这对我(有点强迫症)来说修改让我很难受 开始: 我们去找到虚拟机的这个目录 /www/server/panel/vhost/nginx 然后直接修改下面的文件 修改文件的端口 最…

windows中python安装保姆教程

猜你感兴趣 牛逼的python库-使用Pyinstaller将python打包成exe使用python实现自动点击功能python进程&#xff0c;线程&#xff0c;协程简介快速搭建私有pip镜像源 简介 Python 是一种开源的解释型脚本编程语言&#xff0c;Python简单易用&#xff0c;学习成本低&#xff0c;…

ChatGLM-6B的P-Tuning微调详细步骤及结果验证

文章目录 1. ChatGLM-6B1.1 P-Tuning v2简介 2. 运行环境2.1 项目准备 3.数据准备4.使用P-Tuning v2对ChatGLM-6B微调5. 模型评估6. 利用微调后的模型进行验证6.1 微调后的模型6.2 原始ChatGLM-6B模型6.3 结果对比 1. ChatGLM-6B ChatGLM-6B仓库地址&#xff1a;https://githu…

<<c和指针>>温故及问题研讨(第三章)

第三章-数据 1. 前言2. 基本数据类型2.1 整型家族2.2 字面值常量 3. 基本声明3.1 数组的声明以及引用3.2 指针的声明注意事项3.3 隐式声明 4. 常量5. 作用域5.1 代码块作用域5.2 文件作用域5.3 原型作用域 6. 链接属性6.1 链接属性分类以及作用范围6.2 关键字:extern和static6.…

数据库基础篇 《18.MySQL8其它新特性》

第18章_MySQL8其它新特性 1. MySQL8新特性概述 MySQL从5.7版本直接跳跃发布了8.0版本&#xff0c;可见这是一个令人兴奋的里程碑版本。MySQL 8版本在功能上做了显著的改进与增强&#xff0c;开发者对MySQL的源代码进行了重构&#xff0c;最突出的一点是多MySQL Optimizer优化…

GPT详细安装教程-GPT软件国内也能使用

GPT (Generative Pre-trained Transformer) 是一种基于 Transformer 模型的自然语言处理模型&#xff0c;由 OpenAI 提出&#xff0c;可以应用于各种任务&#xff0c;如对话系统、文本生成、机器翻译等。GPT-3 是目前最大的语言模型之一&#xff0c;其预训练参数超过了 13 亿个…

LeetCode:206. 反转链表

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340; 算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;206. 反转链表 题目描述&#xff1a;给你单链表的头节点 head &#x…