@楼主,过来帮忙看一下,为什么我用的共阳极的,改了程序还是没有显示: 一、原理图: 二、STC15ADC.c /********************************************/ //2016.10.20日 1:01编写完成 //作者:刘海龙 (读单片机内部BandGap基准电压值参考的STC官网程序) //硬件:STC15W408AS+3位共阴数码管+2个10K的电阻(1/4w) //晶振无说明的情况选12M //测量口P1.3 #include <STC15W.h> #include <intrins.h> #include<4LED_YIN.H>//数码管驱动显示程序 #include <BandGap.H>//包含读单片机内部BandGap基准电压值 /********************************/ void main (void) { Delay20ms();//待系统稳定 InitADC();//初始化ADC P1M1=0X08;//P1.3高阻输入 init();//IO口设置初始化 while (1) { ShowResult(3);//显示通道P1.3的测量值、单位为毫伏 disp(); //数码管显示电压值 } } 三、4LED_YIN.H /***********四位共阴数码管驱动程序************/ //stc15w单片机 //1在主程序前加上初始化init();程序 //2硬件连接变动时需修改下面的参数 sbit H1 = P1^0;//设置第1位数码管阳极连接的I/O口 sbit H2 = P1^1;//设置第2位数码管阳极连接的I/O口 sbit H3 = P1^2;//设置第3位数码管阳极连接的I/O口 //sbit H4 = P1^7;//设置第4位数码管阳极连接的I/O口 sbit a = P3^7; sbit b = P3^6; sbit c = P3^5; sbit d = P3^4; sbit e = P3^3; sbit f = P3^2; sbit g = P3^1; sbit dp = P3^0; unsigned char PWM;//显示亮度 unsigned int v;//定义测量电压变量 #define P1M0SET 0x00 //设置I/O口工作方式//00000000(左到右,高到低位) #define P1M1SET 0x00 //设置I/O口工作方式//00000000 #define P3M0SET 0xFF //设置I/O口工作方式//11111111 #define P3M1SET 0x00 //设置I/O口工作方式//00000000 /*****以上定义需要根据实际硬件情况更改******/ #define light 9 //设置LED显示的亮度(值域:1~9) #define DELAY_L 12 //设置每一个点显示的时间长度(1~20) /********* 延时函数 ***************/ void delay (unsigned int a){ // 用于点扫描的延时 unsigned int i; while( a-- != 0){ for(i = 0; i < DELAY_L; i++); } } /*********************************************************************************************/ unsigned char code disdata[]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09}; //显示0~9的段码 //数码管:负向位置;共阳极;负向连接 void dis_off (void){ P3 = P3M0SET; //关所有显示 P1 = ~P1M0SET; delay(10-PWM); } /*********************************************************************************************/ void displayHH1 (unsigned char q){ //第1位数码管显示程序 unsigned char i; i = q & 0x7F; if(i == 0x7F){ H1 = 0;a = 0;}delay(PWM);dis_off(); i = q & 0xBF; if(i == 0xBF){ H1 = 0;b = 0;}delay(PWM);dis_off(); i = q & 0xDF; if(i == 0xDF){ H1 = 0;c = 0;}delay(PWM);dis_off(); i = q & 0xEF; if(i == 0xEF){ H1 = 0;d = 0;}delay(PWM);dis_off(); i = q & 0xF7; if(i == 0xF7){ H1 = 0;e = 0;}delay(PWM);dis_off(); i = q & 0xFB; if(i == 0xFB){ H1 = 0;f = 0;}delay(PWM);dis_off(); i = q & 0xFD; if(i == 0xFD){ H1 = 0;g = 0;}delay(PWM);dis_off(); i = q & 0xFE; if(i == 0xFE){ H1 = 0;dp = 0;}delay(PWM);dis_off(); } /*********************************************************************************************/ void displayHH2 (unsigned char q){ //第2位数码管显示程序 unsigned char i; i = q & 0x7F; if(i == 0x7F){ H2 = 0;a = 0;}delay(PWM);dis_off(); i = q & 0xBF; if(i == 0xBF){ H2 = 0;b = 0;}delay(PWM);dis_off(); i = q & 0xDF; if(i == 0xDF){ H2 = 0;c = 0;}delay(PWM);dis_off(); i = q & 0xEF; if(i == 0xEF){ H2 = 0;d = 0;}delay(PWM);dis_off(); i = q & 0xF7; if(i == 0xF7){ H2 = 0;e = 0;}delay(PWM);dis_off(); i = q & 0xFB; if(i == 0xFB){ H2 = 0;f = 0;}delay(PWM);dis_off(); i = q & 0xFD; if(i == 0xFD){ H2 = 0;g = 0;}delay(PWM);dis_off(); i = q & 0xFE; if(i == 0xFE){ H2 = 0;dp = 0;}delay(PWM);dis_off(); } /*********************************************************************************************/ void displayHH3 (unsigned char q){ //第3位数码管显示程序 unsigned char i; i = q & 0x7F; if(i == 0x7F){ H3 = 0;a = 0;}delay(PWM);dis_off(); i = q & 0xBF; if(i == 0xBF){ H3 = 0;b = 0;}delay(PWM);dis_off(); i = q & 0xDF; if(i == 0xDF){ H3 = 0;c = 0;}delay(PWM);dis_off(); i = q & 0xEF; if(i == 0xEF){ H3 = 0;d = 0;}delay(PWM);dis_off(); i = q & 0xF7; if(i == 0xF7){ H3 = 0;e = 0;}delay(PWM);dis_off(); i = q & 0xFB; if(i == 0xFB){ H3 = 0;f = 0;}delay(PWM);dis_off(); i = q & 0xFD; if(i == 0xFD){ H3 = 0;g = 0;}delay(PWM);dis_off(); i = q & 0xFE; if(i == 0xFE){ H3 = 0;dp = 0;}delay(PWM);dis_off(); } void diplay_data (unsigned char l,unsigned char q){ switch (l){//显示的数码管位置 case 1:// displayHH1(q); //将显示数据送入 break;// case 2:// displayHH2(q); //将显示数据送入 break;// case 3:// displayHH3(q); //将显示数据送入 break;// // case 4:// // displayHH4(q); //将显示数据送入 // break;// } } /*****************IO口初始化**************************/ void init (void){ P3M1=P3M1SET; P3M0=P3M0SET; P1M0=P1M0SET; P1M1=P1M1SET; dis_off(); PWM = light;} /*******************************************/ /******************显示程序*************************/ void disp(){ unsigned int i; for(i=0;i<50;i++){ diplay_data (1,disdata[v/1000]+0x80); diplay_data (2,disdata[v%1000/100]); diplay_data (3,disdata[v%100/10]); } } 四、BandGap.H //内部BandGap为基准测电压 //----------------------------------------- #define uchar unsigned char #define uint unsigned int unsigned int v; //ADC相关设定参数 #define ADC_POWER 0x80 //ADC电源控制位 #define ADC_FLAG 0x10 //ADC完成标志 #define ADC_START 0x08 //ADC起始控制位 #define ADC_SPEEDLL 0x00 //540个时钟 #define ADC_SPEEDL 0x20 //360个时钟 #define ADC_SPEEDH 0x40 //180个时钟 #define ADC_SPEEDHH 0x60 //90个时钟 //----------------------------------------- //BandGap相关参数 //注意:需要在下载代码时选择"在ID号前添加重要测试参数"选项,才可在程序中获取此参数 //#define ID_ADDR_ROM 0x03f7 //1K程序空间的MCU //#define ID_ADDR_ROM 0x07f7 //2K程序空间的MCU //#define ID_ADDR_ROM 0x0bf7 //3K程序空间的MCU //#define ID_ADDR_ROM 0x0ff7 //4K程序空间的MCU //#define ID_ADDR_ROM 0x13f7 //5K程序空间的MCU #define ID_ADDR_ROM 0x1ff7 //8K程序空间的MCU //#define ID_ADDR_ROM 0x27f7 //10K程序空间的MCU //#define ID_ADDR_ROM 0x2ff7 //12K程序空间的MCU //#define ID_ADDR_ROM 0x3ff7 //16K程序空间的MCU //#define ID_ADDR_ROM 0x4ff7 //20K程序空间的MCU //#define ID_ADDR_ROM 0x5ff7 //24K程序空间的MCU //#define ID_ADDR_ROM 0x6ff7 //28K程序空间的MCU //#define ID_ADDR_ROM 0x7ff7 //32K程序空间的MCU //#define ID_ADDR_ROM 0x9ff7 //40K程序空间的MCU //#define ID_ADDR_ROM 0xbff7 //48K程序空间的MCU //#define ID_ADDR_ROM 0xcff7 //52K程序空间的MCU //#define ID_ADDR_ROM 0xdff7 //56K程序空间的MCU //#define ID_ADDR_ROM 0xeff7 //60K程序空间的MCU //----------------------------------------- //声明 void Delay20ms() //@12.000MHz { unsigned char i, j, k; _nop_(); _nop_(); i = 1; j = 234; k = 113; do { do { while (--k); } while (--j); } while (--i); } /*---------------------------- 初始化ADC ----------------------------*/ void InitADC() { P1ASF = 0x00; //不设置P1口为AD口 ADC_RES = 0; //清除结果寄存器 ADC_CONTR = ADC_POWER | ADC_SPEEDLL; Delay20ms(); } /*---------------------------- 读取ADC结果 ----------------------------*/ uint GetADCResult(uchar ch) { uint ADC_10BIT_RES; ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START; _nop_(); //等待4个NOP _nop_(); _nop_(); _nop_(); while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成 ADC_CONTR &= ~ADC_FLAG; //关闭 ADC ADC_10BIT_RES=ADC_RES; //得到高8位 ADC_10BIT_RES<<=2; ADC_10BIT_RES+=ADC_RESL; //得到低2位 return ADC_10BIT_RES; //返回ADC结果 } /*---------------------------- 发送ADC结果 ----------------------------*/ void ShowResult(uchar ch) { uint adc_res10,//测量设定通道adc值 bandgap, //bandgap预储存校准值,单位毫伏 adc_9gallery_res; //测量第九通道(bandgap)值 float power_voltage, //系统供电电压,单位毫伏 ADC_voltage; //设定通道电压值,单位毫伏 uchar code *cptr; //定义ROM(代码)区指针 //uchar idata *iptr;//定义RAM(内存)区指针 cptr = ID_ADDR_ROM; //从程序区读取BandGap电压值(单位:毫伏mV) bandgap=*cptr++; bandgap<<=8; bandgap+=*cptr; /*iptr = ID_ADDR_RAM; //从内存区读取BandGap电压值(单位:毫伏mV) bandgap=*iptr++; //两种方法结果一样,上面的方法需要在下载式勾选"在ID号前添加重要测试参数"选项,才可在程序中获取此参数 bandgap<<=8; //下面的方法不需要 bandgap+=*iptr; */ //测量设定通道adc值 ADC_RES = 0; //清除结果寄存器 P1ASF = 0x08; //设置P1.3口为AD口 GetADCResult(ch); GetADCResult(ch); //读三次获得稳定 adc_res10= GetADCResult(ch); //测量第九通道(bandgap)值 ADC_RES = 0; //清除结果寄存器 P1ASF = 0x00; //设置读第九通道 GetADCResult(0); //测bandgap时,调用此函数时通道数只能填0 GetADCResult(0); //读三次获得稳定 adc_9gallery_res=GetADCResult(0); //计算系统供电电压 power_voltage=(float)bandgap*1024/adc_9gallery_res; //计算ADC通道测得电压值 ADC_voltage=(float)bandgap*adc_res10/adc_9gallery_res; v=ADC_voltage; v=v*2; } |
原理图.jpg (185.98 KB, 下载次数: 998)
原理图
你发帖子,我点赞,鼓励继续做贡献 |
新手入门,学习中,感谢分享! |
好文章,我现在才看到![]() |
谢谢分享! |
单片机学习中,向无私分享的大神们致敬! |
好文章,学习了,收益很大! |
越快乐越堕落 发表于 2017-5-4 11:11 虽然我来的晚,但是我看见楼主说了,这个表量程9.9V,你要测量30.5V那肯定出问题, |
a185980800 发表于 2024-2-23 22:34 探讨程序校准,硬件校准没有意义 |
gpdt3209 发表于 2022-11-15 13:48 把R1换成多圈可调电阻,就可以校准了 |
taoran 发表于 2016-10-20 19:52 应该是AD |
楼主分享的很有用,辛苦楼主了,这个改4位也好改吧![]() |
手頭剛好友幾個stc15w408as,有空拿來做電壓電流表似乎有不錯,謝樓主。 |
支持努力实践并分享成果的人 |
很好的资料,收藏学习!谢谢分享 |
数码管不亮,测了位选高电平4.6V,段选也是高电平4.48V |
都是牛人啊,下去用protues仿真测试一下下 |
很好的东西,值得学习,准备试试。 |
很好,值得分享,建议单片机多IO口都没用,可以做成双路现实的,实现电压、电流同时测试、显示。 |
简单实用,新意构思,值得学习。 |
fmdpj 发表于 2022-6-24 14:13 我没分,下不了。应该还有H文件 |
楼主的设计简单、实用,适合初学仿制。 |
增加标定校准功能就准了,哪位大师可以改改 |
很好,值得点赞和学习 |
就喜欢这简洁的设计,内部基准精度应该够用,现在影响精度的是外部电阻, |
程序中 //计算系统供电电压 power_voltage=(float)bandgap*1024/adc_9gallery_res; 多余了,没用到,浪费算力 |
楼主还会来看吗?我下载了附件,源代码就怎么就这么一点点 ********************************************/ //2016.10.20日 1:01编写完成 //作者:刘海龙 (读单片机内部BandGap基准电压值参考的STC官网程序) //硬件:STC15W408AS+3位共阴数码管+2个10K的电阻(1/4w) //晶振无说明的情况选12M //测量口P1.7 #include <STC15W.h> #include <intrins.h> #include<4LED_YIN.H>//数码管驱动显示程序 #include <BandGap.H>//包含读单片机内部BandGap基准电压值 /********************************/ void main (void) { Delay20ms();//待系统稳定 InitADC();//初始化ADC P1M1=0X80;//P1.7高阻输入 init();//IO口设置初始化 while (1) { ShowResult(7);//显示通道P1.7的测量值、单位为毫伏 disp(); //数码管显示电压值 } } |
wjqzywmm 发表于 2021-7-19 18:43 你好!能否把完整的源代码分享给我,先谢谢了 |
要是能移植到储能点焊机控制板里面,用于监视储能电容电压,这样就不用另外配个电压表,不会玩单片机只能看看 |
大神:LED没有限流电阻,这个方案是如何控制电流,避免LED和MCU过流损坏的呢? |
原理很好,但有不理解的地方:一般而言,用限流电阻控制各LED的电流,目前的方案是以什么方式控制LED电流,以减少LED及MCU的过电流损坏?? |
hewe_001 发表于 2021-7-13 01:21 我驱动4为共阳的方法,电路图相同,供参考: unsigned char code disdata[]={ 0x01,0x4F,0x12,0x06,0x4C, 0x24,0x20,0x0D,0x00,0x04};//0-9 void dis_off (){ P3 = 0xFF; //P3对应笔画,关所有显示 H2=1;H4=1; H1=1;H3=1; delay(10-light); } void dispNum (unsigned char q,unsigned char dot){ //dot=1为显示小数点; unsigned char x; x=disdata[q]; dp=1-dot; a=x>>6 & 0x01; b=x>>5 & 0x01; c=x>>4 & 0x01; d=x>>3 & 0x01; e=x>>2 & 0x01; f=x>>1 & 0x01; g=x & 0x01; } /******************显示程序*************************/ void disp(){ unsigned int ii; unsigned int vv; unsigned char i; for(ii=0;ii<50;ii++){ i=v%10; //我用的是四位led,所以这里的v=原始v/10 vv=v-i; H1=0;dispNum(i,0);delay(light);dis_off(); i=(vv/10)%10; vv=vv-10*i; H2=0;dispNum(i,0);delay(light);dis_off(); i=(vv/100)%10; vv=vv-100*i; H3=0;dispNum(i,1);delay(light);dis_off(); //第三位显示小数点 i=(vv/1000)%10; if(i>0){ H4=0;dispNum(i,0);delay(light);dis_off(); //第四位是0,不显示 } } } |
真够简单的,正好想做一个,感谢楼主分享!!! |
你发帖子,我点赞,鼓励继续做贡献! |
刘海龙 发表于 2016-10-20 16:39 下载时已经勾选了! |
留个记号 有时间了来学习一下,谢谢大神们。 |
电路简洁,先收藏一下 |
楼主能不能改个共阳的程序? 或者在4LED_YIN.h中指明一下,怎样修改? |