本次学习PCF8591.
PCF8591是一个ADC转化器, 可以将板子上采集的模拟量转化为数字量.
使用蓝桥杯官方提供的IIC驱动代码, 我们只需要写PCF8591的初始化和读取数据的代码就好.
多说无益,贴上代码:
iic.c:
/* 程序说明: IIC总线驱动程序 软件环境: Keil uVision 4.10 硬件环境: CT107单片机综合实训平台(12MHz) 日 期: 2011-8-9 */ #include "iic.h" //总线启动条件 void IIC_Start(void) { SDA = 1; SCL = 1; somenop; SDA = 0; somenop; SCL = 0; } //总线停止条件 void IIC_Stop(void) { SDA = 0; SCL = 1; somenop; SDA = 1; } //应答位控制 void IIC_Ack(unsigned char ackbit) { if(ackbit) { SDA = 0; } else { SDA = 1; } somenop; SCL = 1; somenop; SCL = 0; SDA = 1; somenop; } //等待应答 bit IIC_WaitAck(void) { SDA = 1; somenop; SCL = 1; somenop; if(SDA) { SCL = 0; IIC_Stop(); return 0; } else { SCL = 0; return 1; } } //通过I2C总线发送数据 void IIC_SendByte(unsigned char byt) { unsigned char i; for(i=0;i<8;i++) { if(byt&0x80) //如果byte最高位是0,那么成立 { SDA = 1; } else { SDA = 0; } somenop; SCL = 1; byt <<= 1; somenop; SCL = 0; } } //从I2C总线上接收数据 unsigned char IIC_RecByte(void) { unsigned char da; unsigned char i; for(i=0;i<8;i++) { SCL = 1; somenop; da <<= 1; if(SDA) da |= 0x01; SCL = 0; somenop; } return da; } void PCF8591Init(uchar channel) { //时序:开始-发送主机地址-发送通道数-停止(期间有等待应答) IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck(); IIC_SendByte(channel); IIC_WaitAck(); IIC_Stop(); } uchar PCF8591ReadData() { //时序:开始-发送主机地址-返回数据-停止(期间有等待应带) uchar dat; IIC_Start(); IIC_SendByte(0x91); IIC_WaitAck(); dat = IIC_RecByte(); IIC_Ack(0); IIC_Stop(); return dat; }
iic.h:
#ifndef _IIC_H #define _IIC_H #include "regx52.h" #include "intrins.h" #define somenop {\ _nop_();_nop_();_nop_();_nop_();_nop_();\ _nop_();_nop_();_nop_();_nop_();_nop_();\ _nop_();_nop_();_nop_();_nop_();_nop_();\ _nop_();_nop_();_nop_();_nop_();_nop_();\ _nop_();_nop_();_nop_();_nop_();_nop_();\ _nop_();_nop_();_nop_();_nop_();_nop_();} #define SlaveAddrW 0xA0 #define SlaveAddrR 0xA1 typedef unsigned int uint; typedef unsigned char uchar; //总线引脚定义 sbit SDA = P2^1; /* 数据线 */ sbit SCL = P2^0; /* 时钟线 */ //函数声明 void IIC_Start(void); void IIC_Stop(void); void IIC_Ack(unsigned char ackbit); void IIC_SendByte(unsigned char byt); bit IIC_WaitAck(void); unsigned char IIC_RecByte(void); void PCF8591Init(uchar channel); uchar PCF8591ReadData(); #endif
main.c:
/* 实现的效果为旋转板子上的第一个电位器,数码管会显示当前电位器的值 */ #include "iic.h" sbit BUZZ = P0^6; sbit RELAY = P0^4; uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90, 0xff}; uchar DisplayData[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; uchar ADCValue=0; uint n=0; void CloseBUZZ(); void CloseLED(); void ChooseNixie(uchar site,uchar num); void Display(); void Delay(uint i); void main() { TMOD |= 0x01; TH0=0xFF; TL0=0x9C; EA=1; ET0=1; TR0=1; CloseBUZZ(); CloseLED(); PCF8591Init(0x03); while (1) { Display(); } } void Timer0() interrupt 1 { n++; TH0=0xFF; TL0=0x9C; if (n==100) { //每隔时间采集一次AD值 ADCValue = PCF8591ReadData(); n=0; } } void Display() { uchar displayNum=0; DisplayData[7] = table[ADCValue%10]; DisplayData[6] = table[ADCValue%100/10]; DisplayData[5] = table[ADCValue/100]; for (displayNum=5;displayNum<8;displayNum++) { ChooseNixie(displayNum,DisplayData[displayNum]); Delay(60); } } //搬砖代码 void ChooseNixie(uchar site,uchar num) { P0=0xff; P2=(P2&0x1f)|0xe0; P2&=0x1f; P0=1<<site; P2=(P2&0x1f)|0xc0; P2&=0x1f; P0=num; P2=(P2&0x1f)|0xe0; P2&=0x1f; } void CloseBUZZ() { BUZZ=0; RELAY=0; P2=(P2&0x1f)|0xa0;P2&=0x1f; } void CloseLED() { P0=0xff; P2=(P2&0x1f)|0x80; P2&=0x1f; } void Delay(uint i) { while (i--); }
显示的效果为旋转第一个电位器会在数码管上显示当前电位器的值.