本次学习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--);
}
显示的效果为旋转第一个电位器会在数码管上显示当前电位器的值.