可以随便使用
请大家多多指教 ADC0832芯片
1、本设计基于STC89C51/52(与AT89S51/52、AT89C51/52通用)。
2、支持电压,电流,电阻测量,通过数码管显示它们的数值
3、开关切换测量电压、电流、电阻。通过调节滑动变阻器来改变它们的大小。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
- #include "intrins.h"
- #define u8 unsigned char
- #define u16 unsigned int
- #define uchar unsigned char
- #define uint unsigned int
-
- //按键
- sbit Key_V=P3^0; //电压模式键
- sbit Key_R=P1^4; //电阻模式键
- sbit Key_I=P3^5; //电流模式键
- sbit Speak=P3^1; //电流模式键
- #define KEY_V 1 //电压模式
- #define KEY_R 2 //电阻模式
- #define KEY_I 3 //电流模式
- /***********************************************************************************************************
- 数码管显示相关函数
- ***********************************************************************************************************/
- #define SMG_NUM 4
- u8 code DisplayNum[16]={
- 0xc0, //0
- 0x8e //F
- };
- //
- u8 code DisplayOther[]={
- 0xff, //0 空
- 0x7f, //1 "."
- 0xbf, //2 "-"
- 0xa7 //3 c
- };
- /********************************************************************
- * 名称 : delay_1ms()
- * 功能 : 延时1ms函数
- * 输入 : q
- * 输出 : 无
- ***********************************************************************/
- void delay_ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<110;j++);
- }
- //数码管位选定义
- sbit smg_we1 = P2^0; //数码管1
- sbit smg_we2 = P2^1; //数码管2
- sbit smg_we3 = P2^2; //数码管3
- sbit smg_we4 = P2^3; //数码管4
- /***********************数码位选函数*****************************/
- //i: 0,数码管1
- // 1,数码管2
- // 2,数码管3
- // 3,数码管4
- void smg_we_switch(uchar i)
- {
- switch(i)
- {
- case 0: smg_we1 = 0; smg_we2 = 1; smg_we3 = 1; smg_we4 = 1; break;
- case 1: smg_we1 = 1; smg_we2 = 0; smg_we3 = 1; smg_we4 = 1; break;
- case 2: smg_we1 = 1; smg_we2 = 1; smg_we3 = 0; smg_we4 = 1; break;
- case 3: smg_we1 = 1; smg_we2 = 1; smg_we3 = 1; smg_we4 = 0; break;
- }
- }
- /********************************************************************
- * 名称 : delay_1ms()
- * 功能 : 延时1ms函数
- * 输入 : q
- * 输出 : 无
- ***********************************************************************/
- void delay_1ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<110;j++);
- }
- /********************************************************************
- * 名称 : u8 ChangeFor(u8 dat)
- * 功能 : 交换一个字节位的位置,用于数码管显示
- * 输入 : 需要改变的数
- * 输出 : 改变后的数
- ***********************************************************************/
- #define LED_a 0 //数码管段选的a段接在段选IO口的第0位
- #define LED_b 2
- #define LED_c 6
- #define LED_d 4
- #define LED_e 3
- #define LED_f 1
- #define LED_g 7
- #define LED_dp 5
- u8 ChangeFor(u8 dat)
- {
- u8 temp=0;
- if(dat&0x01) //判断数据的第一位是否为1
- temp|=0x01<<LED_a;//如果为1,放到控制数码管a段的位置
- if(dat&0x02)
- temp|=0x01<<LED_b;
- if(dat&0x04)
- temp|=0x01<<LED_c;
- if(dat&0x08)
- temp|=0x01<<LED_d;
- if(dat&0x10)
- temp|=0x01<<LED_e;
- if(dat&0x20)
- temp|=0x01<<LED_f;
- if(dat&0x40)
- temp|=0x01<<LED_g;
- if(dat&0x80)
- temp|=0x01<<LED_dp;
- return temp;
- }
- uchar dis_smg[SMG_NUM]; //显示缓存数组
- /********************************************************************
- * 名称 : display()
- * 功能 : 数码管显示
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void DisplayScan()
- {
- static uchar i;
- P0 = 0xff; //消隐
- smg_we_switch(i); //位选
- P0 = ChangeFor(dis_smg[i]); //段选
- i++;
- if(i>=SMG_NUM)
- i=0;
- }
- /***********************************************************************************************************
- ADC0832相关函数
- ***********************************************************************************************************/
- sbit ADCS =P1^2; //ADC0832 片选
- sbit ADCLK =P1^0; //ADC0832 时钟
- sbit ADDI =P1^1; //ADC0832 数据输入 /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
- sbit ADDO =P1^1; //ADC0832 数据输出 /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上
- //========================================================================
- // 函数: unsigned int Adc0832(unsigned char channel)
- // 应用: temp=Adc0832(0);
- // 描述: 读取0通道的AD值
- // 参数: channel:通道0和通道1选择
- // 返回: 选取通道的AD值
- // 版本: VER1.0
- // 日期: 2015-05-29
- // 备注:
- //========================================================================
- unsigned int Adc0832(unsigned char channel)
- {
- uchar i=0;
- uchar j;
- uint dat=0;
- uchar ndat=0;
- uchar Vot=0;
- if(channel==0)channel=2;
- if(channel==1)channel=3;
- ADDI=1;
- _nop_();
- _nop_();
- ADCS=0;//拉低CS端
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿1
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=channel&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿2
- _nop_();
- _nop_();
- ADCLK=1;//拉高CLK端
- ADDI=(channel>>1)&0x1;
- _nop_();
- _nop_();
- ADCLK=0;//拉低CLK端,形成下降沿3
- ADDI=1;//控制命令结束
- _nop_();
- _nop_();
- dat=0;
- for(i=0;i<8;i++)
- {
- dat|=ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- dat<<=1;
- if(i==7)dat|=ADDO;
- }
- for(i=0;i<8;i++)
- {
- j=0;
- j=j|ADDO;//收数据
- ADCLK=1;
- _nop_();
- _nop_();
- ADCLK=0;//形成一次时钟脉冲
- _nop_();
- _nop_();
- j=j<<7;
- ndat=ndat|j;
- if(i<7)ndat>>=1;
- }
- ADCS=1;//拉低CS端
- ADCLK=0;//拉低CLK端
- ADDO=1;//拉高数据端,回到初始状态
- dat<<=8;
- dat|=ndat;
- return(dat); //return ad data
- }
- /***********************************************************************************************************
- 主函数
- ***********************************************************************************************************/
- void main (void)
- {
- u8 Mode;
- uchar Read_AD; //用于读取ADC数据
- uchar VIN; //电压值变量
- u16 RIN; //电阻值变量
- u16 IIN; //电流值变量
- u16 i=0;;
- while (1) //主循环
- {
- if(Key_V==0) //电压按键按下
- {
- Key_V=1; //清除按下标记
- if((Key_R==0)||(Key_I==0))//电阻电流按键也有按下
- {
- Key_I=1;
- Key_R=1;
- Key_V=1;
- Mode=4; //标记为错误模式
- }
- else //电阻电流键都没有按下
- Mode=1; //标记为电压模式
- }
- if(Key_R==0) //同电压键
- {
- Key_R=1;
- if((Key_V==0)||(Key_I==0))
- {
- Key_I=1;
- Key_R=1;
- Key_V=1;
- Mode=4;
- }
- else
- Mode=2;
- }
- if(Key_I==0) //同电压键
- {
- Key_I=1;
- if((Key_V==0)||(Key_R==0))
- {
- Key_I=1;
- Key_R=1;
- Key_V=1;
- Mode=4;
- }
- else
- Mode=3;
- }
- if((Key_V==1)&&(Key_R==1)&&(Key_I==1))//都没有按下
- {
- Mode=0; //标记为空闲模式
- }
- if(i==0)
- {
- Read_AD=Adc0832(0); //读取AD值
- }
- i++;
- if(i>300)
- i=0;
- switch(Mode)
- {
- case 0:
- //空闲模式
- dis_smg[0]=DisplayOther[2];//关闭数码管显示
- dis_smg[1]=DisplayOther[2];
- dis_smg[2]=DisplayOther[2];
- dis_smg[3]=DisplayOther[2];
- break;
- case 1:
- //电压模式
- VIN=Read_AD*200/255; //换算出电压值
- dis_smg[0]=DisplayNum[0xa]; //显示电压标志
- dis_smg[1]=DisplayNum[VIN/100%10]; //电压十位
- dis_smg[2]=DisplayNum[VIN/10%10]&0x7f; //电压个位
- dis_smg[3]=DisplayNum[VIN%10]; //电压十分位
-
- if(VIN > 100)
- Speak = 0;
- else
- Speak = 1;
- break;
- case 2:
- //电阻模式
- RIN=Read_AD*100/(255-Read_AD); //换算出电阻值
- dis_smg[0]=DisplayNum[0xb]; //显示电阻标志
- dis_smg[1]=DisplayNum[RIN/100%10]; //电阻百位
- dis_smg[2]=DisplayNum[RIN/10%10]; //电阻十位
- dis_smg[3]=DisplayNum[RIN%10]; //电阻个位
- if(RIN>=1000) //超过或等于1000;
- {
- dis_smg[1]=DisplayOther[2]; //显示"-"
- dis_smg[2]=DisplayOther[2]; //显示"-"
- dis_smg[3]=DisplayOther[2]; //显示"-"
- }
-
- if(RIN > 500)
- Speak = 0;
- else
- Speak = 1;
- break;
- case 3:
- //电流模式
- IIN=4*Read_AD;//单位mA //换算出电流值
- dis_smg[0]=DisplayNum[0xc]; //显示电流标志
- if(IIN<=200) //没有超过范围
- {
- dis_smg[1]=DisplayNum[IIN/100%10]; //电流百位
- dis_smg[2]=DisplayNum[IIN/10%10]; //电流十位
- dis_smg[3]=DisplayNum[IIN%10]; //电流个位
- }
- else
- {
- dis_smg[1]=DisplayOther[2]; //显示"-"
- .....代码详见附件.....
复制代码
Keil代码与Proteus7.8与8.13仿真和文档下载:
基于51单片机数字万用表测电压电流电阻仿真设计.7z
(1.02 MB, 下载次数: 81)
|