在数逻的课程中,已经学习过AD转换的概念:将模拟信号采样、量化、编码后转换为数字信号。但是未学习过通过单片机编程,显示结果。
编码分有舍有入、只舍不入两种,量化误差前者更小。=2Vm/(2^n+1 - 1 )
注意,为了达到精确度高、稳定性好的目的,最好将所有器件的模拟地和数字分别连接,最后将模拟地和数字地仅在一点相连。
此处,使用的是STC12C5A60S2内部的AD转换。
1 /* 功能:使用12C5A60S2内部AD读取外部电压,显示在1602上 */ 2 3 #include "STC12C5A60S2.H" 4 #include <intrins.h> 5 sbit RS = P2^6; //1602定义口 //HZ:EN=P2.2 RS=P2.0 RW=P2.1 6 sbit RW = P2^5; 7 sbit EN = P2^7; 8 #define uchar unsigned char; 9 #define uint unsigned int; 10 11 #define RS_CLR RS=0 12 #define RS_SET RS=1 13 #define RW_CLR RW=0 14 #define RW_SET RW=1 15 #define EN_CLR EN=0 16 #define EN_SET EN=1 17 18 #define DataPort P0 //连接1602数据口 P0 19 20 uchar da1=0,da2=0,da3=0; 21 double Data,c; 22 char a[5]=""; 23 uchar ADC_Chanul_Turn=0; 24 25 26 void DelayUs2x(unsigned char t) 27 { 28 while(--t); 29 } 30 31 32 void DelayMs(unsigned char t) 33 { 34 35 while(t--) 36 { 37 //大致延时1mS 38 DelayUs2x(245); 39 DelayUs2x(245); 40 } 41 } 42 /*------------------------------------------------ 43 判忙函数 44 ------------------------------------------------*/ 45 bit LCD_Check_Busy(void) 46 { 47 DataPort= 0xFF; 48 RS_CLR; 49 RW_SET; 50 EN_CLR; 51 _nop_(); 52 EN_SET; 53 return (bit)(DataPort & 0x80); 54 } 55 /*--------- 56 ------------------------------------------------*/ 57 void LCD_Write_Com(unsigned char com) 58 { 59 while(LCD_Check_Busy()); //忙则等待 60 RS_CLR; 61 RW_CLR; 62 EN_SET; 63 DataPort= com; // 64 _nop_(); 65 EN_CLR; 66 } 67 /*------------------------------------------------ 68 写入数据函数 69 ------------------------------------------------*/ 70 void LCD_Write_Data(unsigned char Data) 71 { 72 while(LCD_Check_Busy()); //忙则等待 73 RS_SET; 74 RW_CLR; 75 EN_SET; 76 DataPort= Data; 77 _nop_(); 78 EN_CLR; 79 } 80 81 /*------------------------------------------------ 82 清屏函数 83 ------------------------------------------------*/ 84 void LCD_Clear(void) 85 { 86 LCD_Write_Com(0x01); 87 DelayMs(5); 88 } 89 /*------------------------------------------------ 90 写入字符串函数 91 ------------------------------------------------*/ 92 void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)//y为行数,x为横坐标,最后一个是字符 93 { 94 if (y == 0) 95 { 96 LCD_Write_Com(0x80 + x); //表示第一行 97 } 98 else 99 { 100 LCD_Write_Com(0xC0 + x); //表示第二行 101 } 102 while (*s) 103 { 104 LCD_Write_Data( *s); 105 s ++; 106 } 107 } 108 /*------------------------------------------------ 109 写入字符函数 110 ------------------------------------------------*/ 111 void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) 112 { 113 if (y == 0) 114 { 115 LCD_Write_Com(0x80 + x); 116 } 117 else 118 { 119 LCD_Write_Com(0xC0 + x); 120 } 121 LCD_Write_Data( Data); 122 } 123 /*------------------------------------------------ 124 初始化函数 125 ------------------------------------------------*/ 126 void LCD_Init(void) 127 { 128 LCD_Write_Com(0x38); /*显示模式设置*/ 129 DelayMs(5); 130 LCD_Write_Com(0x38); 131 DelayMs(5); 132 LCD_Write_Com(0x38); 133 DelayMs(5); 134 LCD_Write_Com(0x38); 135 LCD_Write_Com(0x08); /*显示关闭*/ 136 LCD_Write_Com(0x01); /*显示清屏*/ 137 LCD_Write_Com(0x06); /*显示光标移动设置*/ 138 DelayMs(5); 139 LCD_Write_Com(0x0C); /*显示开及光标设置*/ 140 } 141 142 /*------------------------------------------------ 143 ADC函数 144 ------------------------------------------------*/ 145 void InitADC()//初始AD寄存器 146 { 147 P1ASF=0x03; //0xff设置P1口全部为ADC通道,P10 P11为输出口 148 ADC_RES=0x00; //清除高8位缓冲数据 149 if(ADC_Chanul_Turn%2==0) 150 { 151 ADC_CONTR=0xF0; //P10口 152 _nop_(); 153 _nop_(); 154 _nop_(); 155 _nop_(); 156 ADC_CONTR=0xE8; 157 158 } 159 if(ADC_Chanul_Turn%2==1) //P11口 160 { 161 ADC_CONTR=0xF1; 162 _nop_(); 163 _nop_(); 164 _nop_(); 165 _nop_(); 166 ADC_CONTR=0xE9; 167 } 168 } 169 170 void timer0() interrupt 1 //interrupt 1: 定时器0,interrupt3:定时器3 171 { 172 TH0=(65536-20000)/256; //高八位,(需要表示Xms的定时,计数器由65536-X数到65536,由于16位,只能分高低位) 173 TL0=(65536-20000)%256; //低八位 174 InitADC(); 175 176 } 177 178 void adc_isr() interrupt 5 //FLAG标志位置位触发中断,没有设优先级,但是同优先级下定时器0更高 179 { 180 181 //V_5REF=V_1REF*256/da_ref; 182 if(ADC_Chanul_Turn%3==0) //外部基准电压 183 { 184 da1=ADC_RES; //获取转换结果 185 Data=((double)da1/256)*5; //取八位计算基准电压Data, 186 c =Data; 187 } 188 if(ADC_Chanul_Turn%3==1) 189 { 190 da2=ADC_RES; //获取转换结果 191 Data=((double)da2/256)*5; //取八位计算实际值Data, 192 c =Data; 193 } 194 if(ADC_Chanul_Turn%3==2) 195 { 196 da3=ADC_RES; //获取转换结果 197 Data=((double)da3/256)*5; //取八位计算实际值Data, 198 c =Data; 199 } 200 201 a[0]=((int)c%10+0x30);//个位(电压<5,仅有个) //0x30: ASCAI码里代表“0”,必须转换成字符存在字符型数组里才可以在1602液晶屏上显示 202 a[1]=0x2e; //小数点 203 a[2]=((int)(c*10)%10+0x30); // 十分位 204 a[3]=((int)(c*100)%10+0x30);// 百分位 205 a[4]=‘\0‘; // 加了串尾符才成了字符串哦 206 207 if(ADC_Chanul_Turn%3==0) LCD_Write_String(0,0,a); 208 if(ADC_Chanul_Turn%3==1) LCD_Write_String(5,0,a); 209 if(ADC_Chanul_Turn%3==2) LCD_Write_String(0,1,a); 210 211 ADC_CONTR&=0xEF; //标志位清零 212 213 ADC_Chanul_Turn++; 214 if(ADC_Chanul_Turn==252) 215 ADC_Chanul_Turn=0; 216 } 217 void main() 218 { 219 LCD_Init(); 220 LCD_Clear(); //清屏 221 DelayMs(255); 222 TH0=(65536-20000)/256; //开定时器0 223 TL0=(65536-20000)%256; 224 EA=1; //开全局中断 225 ET0=1; //允许定时器零中断 226 EADC=1; //允许ADC中断 227 TR0=1; 228 while(1); 229 }
时间: 2024-10-07 16:13:01