逐次逼近式AD转换器
这是一个基本原理图
首先,内部产生一个参考电压Vref,然后与要进行测量的电压Vin进行比较,如果Vref<=Vin,就产生一个“1”信号(否则产生“0”信号),并存储到N位寄存器的最高位,然重新生成参考电压信号Vref = Vref+0.5Vref,(如果前面产生的是“0”信号,则新的参考电压Vref = 0.5Vref),再与Vin比较,将比较结果(“0”或“1”存到寄存器的下一位),循环往复,直到N位寄存器全部存满数据,最后通过锁存器输出转化后的数字信号。
比如:Vin = 3.75V, Vref = 2.5V
Vref=2.5 < 3.75,因此寄存器最高位存储数据1,然后重新生成Vref = 2.5+0.5*2.5 = 3.75
此时Vref=3.75 == Vin, 返回比较结果1, 存储下来, 然后重新生成Vref = 3.75+3.75*0.5 = 5.6
此时Vref=5.6 > Vin,返回比较结果0,存储下来。。。。。
最后结果是:1100 0000
PCF8591模块
简介
PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入、一个输出和一个串行 I2C 总线接口;
3个地址引脚A0、A1 和 A2 用于编程硬件地址,允许将最多8个器件连接至I2C总线而不需要额外硬件;
PCF8591由于其使用的简单方便和集成度高,在单片机应用系统中得到了广泛的应用。
特点:
单电源供电
工作电压:2.5 V ~ 6 V
I2C总线串行输入/输出
通过3个硬件地址引脚编址
采样速率取决于 I2C 总线传输速率决定
4个模拟输入可编程为单端或差分输入
自动增量通道选择
8位逐次比较型 A/D 转换
管脚定义:
AIN0~AIN3:模拟量输入通道
AOUT:模拟输出通道
A0~A2:硬件设备地址
VDD:电源正极
VSS:电源负极
VREF:参考电压输入。
EXT:振荡器输入时,内部/外部的切换开关。
OSC:振荡器输入/输出。
SCL:I2C BUS时钟输入。
SDA:I2C BUS 数据输入/输出。
AGND:模拟地,模拟信号和基准电源的参考地
开发板中的PCF8591接线:
PCF8591地址
I2C 总线系统中的每一片PCF8591 通过发送有效地址到该器件来激活。该地址包括固定部分和可编程部分
可编程部分必须根据地址引脚A0、A1 和 A2 来设置,因此I2C系统中最多可接8个PCF8591
在I2C 总线协议中地址必须是起始条件后作为第一个字节发送。
地址字节的最后一位是用于设置以后数据传输方向的读/写位(1为读操作,0为写操作)
PCF8591控制字节
发送到 PCF8591 的第二个字节 将被存储在控制寄存器,用于控制器件功能。
控制寄存器的高半字节用于允许模拟输出,以及可以将模拟输入编程为单端或差分输入。
低半字节选择一个由高半字节定义的模拟输入通道。如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。
例子
(一)
利用I2C通信,PCF8591模数/数模转换,读取通道2电位器模拟量,通过数码管显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 #include <reg52.h> #include <intrins.h> #define PCF8591ADDR 0X90 #define I2cRead 1 #define I2cWrite 0 #define CH0 0 #define CH1 1 #define CH2 2 #define CH3 3 #define DAout 0x40 #define MAIN_Fosc 11059200UL typedef unsigned char INT8U;typedef unsigned char uchar;typedef unsigned char u8;typedef unsigned int INT16U;typedef unsigned int uint;typedef unsigned int u16;sbit DU = P2^6 ; sbit WE = P2^7 ; sbit SCL = P2^1 ; sbit SDA = P2^0 ; uint num; bit AckFlag; uchar code SMGduan[]= {0x3F , 0x06 , 0x5B , 0x4F , 0x66 , 0x6D , 0x7D , 0x07 , 0x7F , 0x6F ,}; uchar code SMGwei[] = {0xfe , 0xfd , 0xfb , 0xf7 , 0xef , 0xdf , 0xbf , 0x7f }; void delay (INT16U ms) { INT16U i; do { i = MAIN_Fosc / 96000 ; while (--i); }while (--ms); } void delay5us () { #if MAIN_Fosc == 11059200 _nop_(); #elif MAIN_Fosc == 12000000 _nop_(); #elif MAIN_Fosc == 22118400 _nop_(); _nop_(); _nop_(); #endif } void display (INT16U Value) { DU = 0 ; P0 = SMGduan[Value/1000 ]|0x80 ; DU = 1 ; DU = 0 ; WE = 0 ; P0 = SMGwei[0 ]; WE = 1 ; WE = 0 ; delay(3 ); DU = 0 ; P0 = SMGduan[Value%1000 /100 ]; DU = 1 ; DU = 0 ; WE = 0 ; P0 = SMGwei[1 ]; WE = 1 ; WE = 0 ; delay(3 ); DU = 0 ; P0 = SMGduan[Value%100 /10 ]; DU = 1 ; DU = 0 ; WE = 0 ; P0 = SMGwei[2 ]; WE = 1 ; WE = 0 ; delay(3 ); DU = 0 ; P0 = SMGduan[Value%10 ]; DU = 1 ; DU = 0 ; WE = 0 ; P0 = SMGwei[3 ]; WE = 1 ; WE = 0 ; delay(3 ); } void I2cStart () { SCL = 1 ; SDA = 1 ; delay5us(); SDA = 0 ; delay5us(); } void I2cStop () { SCL = 0 ; SDA = 0 ; SCL = 1 ; delay5us(); SDA = 1 ; delay5us(); } bit ReadACK () { SCL = 0 ; SCL = 1 ; delay5us(); if (SDA) { SCL = 0 ; return (1 ); } else { SCL = 0 ; return (0 ); } } void SendACK (bit i) { SCL = 0 ; if (i) SDA = 1 ; else SDA = 0 ; SCL = 1 ; delay5us(); SCL = 0 ; SDA = 1 ; } void I2cSendByte (uchar DAT) { uchar i; for (i=0 ; i<8 ; i++) { SCL = 0 ; if (DAT & 0x80 ) SDA = 1 ; else SDA = 0 ; SCL = 1 ; DAT <<= 1 ; } SCL = 0 ; SDA = 1 ; } uchar I2cReadByte () { uchar i, DAT; for (i=0 ; i<8 ; i++) { DAT <<= 1 ; SCL = 0 ; SCL = 1 ; if (SDA) DAT |= 0X01 ; } return (DAT); } uchar PCF8591Read (uchar Ctrl) { uchar DAT; I2cStart(); I2cSendByte(PCF8591ADDR + I2cWrite); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; I2cSendByte(Ctrl); ReadACK(); I2cStart(); I2cSendByte(PCF8591ADDR + I2cRead); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; DAT = I2cReadByte(); SendACK(1 ); I2cStop(); return (DAT); } void main () { while (1 ) { num = (PCF8591Read(CH2) * 19.53 + 0.5 ); display(num); delay(5 ); } }
(二)
使用I2C通信,PCF8591模数/数模转换,读取通道0光敏模拟量,输出模拟量控制LED10亮度变化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 #include <reg52.h> #include <intrins.h> #define uint unsigned int #define uchar unsigned char #define PCF8591ADDR 0X90 #define I2cRead 1 #define I2cWrite 0 #define CH0 0 #define CH1 1 #define CH2 2 #define CH3 3 #define DAout 0x40 sbit DU = P2^6 ; sbit WE = P2^7 ; sbit SCL = P2^1 ; sbit SDA = P2^0 ; uchar num; bit AckFlag; uchar code SMGduan[]= {0x3F , 0x06 , 0x5B , 0x4F , 0x66 , 0x6D , 0x7D , 0x07 , 0x7F , 0x6F ,}; uchar code SMGwei[] = {0xfe , 0xfd , 0xfb }; void delay (uint z) { uint x,y; for (x = z; x > 0 ; x--) for (y = 114 ; y > 0 ; y--); } void display (uchar i) { static uchar wei; P0 = 0XFF ; WE = 1 ; P0 = SMGwei[wei]; WE = 0 ; switch (wei) { case 0 : DU = 1 ; P0 = SMGduan[i / 100 ]; DU = 0 ; break ; case 1 : DU = 1 ; P0 = SMGduan[i % 100 / 10 ]; DU = 0 ; break ; case 2 : DU = 1 ; P0 = SMGduan[i % 10 ]; DU = 0 ; break ; } wei++; if (wei == 3 ) wei = 0 ; } void timer0Init () { EA = 1 ; ET0 = 1 ; TR0 = 1 ; TMOD |= 0X01 ; TH0 = 0xED ; TL0 = 0xFF ; } void delay5us () { _nop_(); } void I2cStart () { SCL = 1 ; SDA = 1 ; delay5us(); SDA = 0 ; delay5us(); } void I2cStop () { SCL = 0 ; SDA = 0 ; SCL = 1 ; delay5us(); SDA = 1 ; delay5us(); } bit ReadACK () { SCL = 0 ; SCL = 1 ; delay5us(); if (SDA) { SCL = 0 ; return (1 ); } else { SCL = 0 ; return (0 ); } } void SendACK (bit i) { SCL = 0 ; if (i) SDA = 1 ; else SDA = 0 ; SCL = 1 ; delay5us(); SCL = 0 ; SDA = 1 ; } void I2cSendByte (uchar DAT) { uchar i; for (i=0 ; i<8 ; i++) { SCL = 0 ; if (DAT & 0x80 ) SDA = 1 ; else SDA = 0 ; SCL = 1 ; DAT <<= 1 ; } SCL = 0 ; SDA = 1 ; } void Pcf8591DA (uchar Ctrl, DAT) { I2cStart(); I2cSendByte(PCF8591ADDR + I2cWrite); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; I2cSendByte(Ctrl); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; I2cSendByte(DAT); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; I2cStop(); } uchar I2cReadByte () { uchar i, DAT; for (i=0 ; i<8 ; i++) { DAT <<= 1 ; SCL = 0 ; SCL = 1 ; if (SDA) DAT |= 0X01 ; } return (DAT); } uchar PCF8591Read (uchar Ctrl) { uchar DAT; I2cStart(); I2cSendByte(PCF8591ADDR + I2cWrite); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; I2cSendByte(Ctrl); ReadACK(); I2cStart(); I2cSendByte(PCF8591ADDR + I2cRead); if (ReadACK()) AckFlag = 1 ; else AckFlag = 0 ; DAT = I2cReadByte(); SendACK(1 ); I2cStop(); return (DAT); } void main () { timer0Init(); while (1 ) { EA = 0 ; num = PCF8591Read(CH0); Pcf8591DA(DAout, ~num); EA = 1 ; delay(5 ); } } void timer0 () interrupt 1{ TH0 = 0xED ; TL0 = 0xFF ; display(num); }