哈哈007 发表于 2018-5-17 13:27 LCD模块数据不对 |
| 因为电压模块焊错了 |
| 我就看看大神 |
哈哈007 发表于 2018-5-20 14:46 由于使用的单片机和实验板电路不同,改动部分都有注释。 //使用单片机型号:IAP15W4K58S4,1T 使用内部时钟11.0592MHz #include <STC15F2K60S2.H> //STC15系列通用头文件 //#include "reg52.h" #include "intrins.h" typedef unsigned char uchar; typedef unsigned int uint; #define _Nop() _nop_() /*------------------------以下为LCD1602显示模块定义-----------------------*/ unsigned char data_char_table[]= {"0123456789ABCDEF"};//LCD数据 unsigned char Lcd_Dis1_table[] = {"Position:No. "};//第一行显示框架 unsigned char pos_char_table[] = {" D "};// 显示位置 unsigned char Lcd_Dis2_table[] = {"Voltage : V"};//第二行显示框架 unsigned char num_char_table[] = {" 9A.CD V"};// 显示位置 #define lcd_data_port P0 //sbit lcd_rs_port = P2^4; //定义LCD控制端口,根据硬件调整 //sbit lcd_rw_port = P2^3; //sbit lcd_en_port = P2^2; sbit lcd_rs_port = P3^5; //定义LCD控制端口,根据硬件调整 //sbit lcd_rw_port = P2^3;//实验板固定接地,不使用读功能 sbit lcd_en_port = P3^4; sbit LEDa=P2^5; //573LED使能端口 sbit dula=P2^6; //573数码管段使能端口 sbit wela=P2^7; //573数码管位使能端口 void lcd_delay(uchar ms); //LCD1602 延时 //void lcd_busy_wait(); //LCD1602 忙等待 void lcd_command_write(uint command);//LCD1602 命令字写入 void lcd_system_reset(); //LCD1602 初始化 void lcd_char_write(uint x_pos,y_pos,lcd_dat);//LCD1602 字符写入 //void lcd_bad_check();//LCD1602 坏点检查 void Num_to_Disp(uchar i, uint Num);//显示数据处理 void LcdDisp(uchar j, uint num);//液晶显示函数 /*------------------------以下为ADC相应寄存器初始化及端口定义-------------*/ /***** 定义与ADC相关的特殊功能寄存器 *****/ /* 与STC15头文件内容重复 sfr ADC_CONTR = 0xBC; //ADC控制寄存器 sfr ADC_RES = 0xBD; //ADC hight 8-bit result register sfr ADC_RESL = 0xBE; //ADC low 2-bit result register sfr P1ASF = 0x9D; //P1口功能控制寄存器P1ASF sfr P1M0 = 0x92; //I/O模式寄存器 sfr P1M1 = 0x91; //I/O模式寄存器*/ /************定义相应操作位***************/ #define ADC_POWER 0x80 //ADC电源控制位,0:关闭,1:打开 #define ADC_FLAG 0x10 //ADC结束标志位 #define ADC_START 0x08 //ADC启动控制位 #define ADC_SPEEDLL 0x00 //540 clocks___________选择转换速度 /*------------------------以下为相关函数声明------------------------------*/ void InitADC(); //ADC初始化 uint GetADCResult(uchar ch); void Delay(uint n); //延时程序 void delay_1ms(uchar x); uint shuju=0; /*---------------------------- 初始化ADC特殊功能寄存器 -------------------*/ void InitADC( ) { P1ASF = 0xff; //Set P1.0 - P1.7 as analog input port ADC_RES = 0; //Clear previous result ADC_RESL = 0; ADC_CONTR = ADC_POWER | ADC_SPEEDLL ; Delay(20); //ADC power-on delay and Start A/D conversion } /*-------------------------------- ADC 取值 ------------------------------*/ uint GetADCResult(uchar ch) { ADC_CONTR=0x88|ch; //开启AD转换1000 1000 即POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 _nop_(); _nop_(); _nop_(); _nop_();//要经过4个CPU时钟的延时,其值才能够保证被设置进ADC_CONTR 寄存器 // ADC_RES=0xdf; // ADC_RESL=0xef; while(!(ADC_CONTR&0x10)); //等待转换完成 ADC_CONTR&=0xe7; //关闭AD转换,ADC_FLAG位由软件清0 return(ADC_RES*4+ADC_RESL); //返回AD转换完成的10位数据(16进制) } /*---------------------------- LCD1602相应函数 ---------------------------*/ //////////////以下是LCD1602驱动程序//////////////// void lcd_delay(uchar ms)//1ms延时(11.0592MHz 1T) { uint i,j; for(i=ms;i>0;i--) for(j=1150;j>0;j--); } /* void lcd_delay(uchar ms) //LCD1602 延时 { uchar j; while(ms--) for(j=0;j<250;j++); }*/ /* //实验板不使用读功能,用延时代替查忙 void lcd_busy_wait() //LCD1602 忙等待 { lcd_rs_port = 0; // lcd_rw_port = 1; lcd_en_port = 1; lcd_data_port = 0xff; while (lcd_data_port&0x80); lcd_en_port = 0; }*/ void lcd_command_write(uint command) /*LCD1602 命令字写入*/ { // lcd_busy_wait(); lcd_rs_port = 0; // lcd_rw_port = 0; lcd_en_port = 0; lcd_data_port = command; lcd_delay(1); lcd_en_port = 1; lcd_delay(1); lcd_en_port = 0; } void lcd_system_reset() /*LCD1602 初始化*/ { dula=0; //关闭数码管段选 wela=0; //关闭数码管位选 LEDa=0; //关闭LED使能 // lcd_delay(20); // lcd_command_write(0x38); // lcd_delay(100); // lcd_command_write(0x38); // lcd_delay(50); lcd_command_write(0x38); // lcd_delay(10); lcd_command_write(0x08); lcd_command_write(0x01); lcd_command_write(0x06); lcd_command_write(0x0c); } void lcd_char_write(uint x_pos,y_pos,lcd_dat) /*LCD1602 字符写入*/ { x_pos &= 0x0f; /* X位置范围 0~15 */ y_pos &= 0x01; /* Y位置范围 0~ 1 */ if(y_pos==1) x_pos += 0x40; x_pos += 0x80; lcd_command_write(x_pos); // lcd_busy_wait(); lcd_rs_port = 1; // lcd_rw_port = 0; // lcd_en_port = 0; lcd_data_port = lcd_dat; lcd_delay(1); lcd_en_port = 1; lcd_delay(1); lcd_en_port = 0; } /* void lcd_bad_check() //LCD1602 坏点检查 { char i,j; for(i=0;i<2;i++){ for(j=0;j<16;j++) { lcd_char_write(j,i,0xff); } } lcd_delay(200); lcd_delay(200); lcd_delay(200); lcd_delay(100); lcd_delay(200); lcd_command_write(0x01); // clear lcd disp }*/ //////////////////以上是LCD1602驱动程序//////////////// /*----------------------------- 延时程序 ---------------------------*/ void Delay(uint n) { uint x; while (n--) { x = 500; while (x--); } } /*1MS为单位的延时程序*/ void delay_1ms(uchar x) { uchar j; while(x--) { for(j=0;j<125;j++) {;} } } /***************************************************************** 函数: averageValueVolgate() 用途: 求多次采集电压平均值 传入参数:chan是端口号 返回值:Val_Av是多次采样的电压值平均值 ******************************************************************/ float averageValueVolgate(uchar chan) { float voltageValue=0; uchar num; for(num=100;num>0;num--) { voltageValue+=GetADCResult(chan); } voltageValue/=100.0; voltageValue=voltageValue;//*5.0/1024; return (voltageValue); } ///////////////以下为LCD显示数据处理///////////////// void Num_to_Disp(uchar i, uint Num) { float NUM; int xx, yy, zz; NUM = ((Num * 5 + 5) / 1024.0); //计算公式:10-bit A/D Conversion Result = 1024 x (Vin / Vcc) xx = (int)NUM; yy = (int)((NUM - (float)(xx)) * 10); zz = (int)((NUM - (float)(xx)) * 100)%10; num_char_table[9] = data_char_table[xx / 10]; //电压值十位 num_char_table[10]= data_char_table[xx % 10]; //电压值个位 num_char_table[12]= data_char_table[yy]; //电压值小数点后一位 num_char_table[13]= data_char_table[zz]; //电压值小数点后两位 pos_char_table[13]= data_char_table; //当前ADC接口 } //////////////////以下为LCD显示//////////////////// void LcdDisp(uchar j, uint num) { uint i=0; // for (i=0;i<16;i++) //此段代码转移到主函数初始化部分 // { // lcd_char_write(i,0,Lcd_Dis1_table); // lcd_char_write(i,1,Lcd_Dis2_table); //显示框架 // } Num_to_Disp(j, num); lcd_char_write(13,0,pos_char_table[13]); //显示当前ADC接口 for(i = 9; i < 14; i++) { lcd_char_write(i,1,num_char_table); //显示当前电压 } delay_1ms(100); } /*-------------------------------- 主函数 --------------------------------*/ void main() { uchar i; //此段端口配置属IAP15W4K58S4所需,全部为准双向口。 P0M0 = 0x00; P0M1 = 0x00; P1M1 = 0x00; P1M0 = 0x00; P2M0 = 0x00; P2M1 = 0x00; P3M0 = 0x00; P3M1 = 0x00; P4M0 = 0x00; P4M1 = 0x00; P5M0 = 0x00; P5M1 = 0x00; P6M0 = 0x00; P6M1 = 0x00; P7M0 = 0x00; P7M1 = 0x00; lcd_system_reset(); //LCD1602 初始化 // lcd_bad_check(); //LCD1602 坏点检查 P1M1 = 0xFF; //P1.0~P1.7高阻 1111 1111 P1M0 = 0x00; //P1.0~P1.7高阻 0000 0000 InitADC(); //初始化ADC特殊功能寄存器 for (i=0;i<16;i++) { lcd_char_write(i,0,Lcd_Dis1_table); lcd_char_write(i,1,Lcd_Dis2_table); //显示框架 } i=0; while (1) { LcdDisp(i,averageValueVolgate(i)); //液晶1602轮流显示第0~7通道电压值 i++; if(i>7) i=0; Delay(2000); } } |
wulin 发表于 2018-5-19 19:21 我用的是单片机最小的系统,其他的什么都没接,能不能把你修改后的程序发给我看看,我看下是我电路有问题还是程序有问题,拜托了 ![]() ![]() ![]() |
哈哈007 发表于 2018-5-19 16:36 读取范围0~VCC。如果还有问题你要检查硬件电路。 |
wulin 发表于 2018-5-19 07:07 但是这个不是读取不了2.8V以下的电压了吗? |
哈哈007 发表于 2018-5-18 21:49 你这是简单的ADC转换,要求不能太高。如果使用定时器,每20ms取样10或20次(环境中的50Hz共/差模干扰周期),去掉一个最大和最小数,其他数相加后+5(四舍五入算法),取平均值,可以做到很稳定。想绝对稳定什么方法都做不到。 |
wulin 发表于 2018-5-18 15:10 程序是什么啊,要咋改 |
哈哈007 发表于 2018-5-17 21:19 你重复计算:NUM =(Num * 5/ 1024.0); voltageValue=voltageValue*5.0/1024; 并且注释掉了 P1M0 = 0x00; P1M1 = 0xFF; 这是在7通道用两个1K电阻分压VCC的测量结果
|
|
重复计算当然出错 NUM =(Num * 5/ 1024.0); voltageValue=voltageValue*5.0/1024; |
wulin 发表于 2018-5-17 17:23 你好 我这样改以后电压稳定了,初始的电压也为0,就是现在读不了AD,一读才0.01,是怎么回事,能帮我看下嘛?
|
wulin 发表于 2018-5-17 17:23
如果我想把这段滤波程序加进去要怎么加? |
哈哈007 发表于 2018-5-17 16:57 如果只测某1个通道电压:例如第3通道 void main() { uchar i; lcd_system_reset(); //LCD1602 初始化 lcd_bad_check(); //LCD1602 坏点检查 InitADC(); //初始化ADC特殊功能寄存器 P1M1 = 0x3f; //P1.0/P1.5高阻 0011 1111 P1M0 = 0x00; //P1.0/P1.5高阻 0000 0000 while (1) { i = 2; LcdDisp(i, GetADCResult(i)); //液晶1602显示第3通道电压值 Delay(1000); } } |
|
你这个问题,要看你的电路原理图啊,只有程序是看不懂的。 因为你的这个程序,明显是根据电路来写的,还是个比较独特的电路,不是一般常见的电路,所以,看不到电路,就无法回答你的问题。 同时,你也可以看你的电路啊,在没有按键时,P3口是个什么状态,就可以知道还原值了。 |
| 你这个问题,要看你的电路原理图啊,只有程序是看不懂的。 因为你的这个程序,明显是根据电路来写的,还是个比较独特的电路,不是一般常见的电路,所以,看不到电路,就无法回答你的问题。 同时,你也可以看你的电路啊,在没有按键时,P3口是个什么状态,就可以知道还原值了。 |
wulin 发表于 2018-5-17 16:48 我就想要让一个通道读取AD就好了,不想那么多通道来回读取 |
哈哈007 发表于 2018-5-17 13:27 你使用了我在前面回贴的错误设置,原贴已编辑修正如下 /*-------------------------------- 主函数 --------------------------------*/ void main() { uchar i; P1M1 = 0x3f; //P1.0~P1.5高阻 0011 1111 P1M0 = 0x00; //P1.0~P1.5高阻 0000 0000 主循环while (1)里 i = 2; while(i < 7)与P1.0~P1.5设为ADC不符。i 的值是0~5. |
这是我的程序,能帮忙看下有什么问题吗?
|