DAY3 PCF8591

详解参考:

PCF8591芯片的AD/DA转换(适用于蓝桥杯单片机)_pcf8591ad转换-CSDN博客

 写在最前,上面链接更细致,这个只是我的总结了各方内容,把重点挑出来,不具有可读性

易错点:

引脚介绍

  PCF8591有四个模拟信号输入端(模转数),一个输出端(数转模),因为我们一般使用芯片的内部时钟,所以EXT和OSC接地,而VSS和VCC手册里写是用来上电复位的,只需要照着原理图接就行。

发送接收数据

      第一位和第二位 :AD转换的输入通道选择位  00 >>AIN0,  01>>AIN1,  10>>AIN2,  11>>AIN3

      第三位 :自动递增标志位,激活时给1,在每次A/D转换后,读取的通道会自动跳到下一位。

      第四位:无效位

      第五、六位:选择差分输入还是单端输入(如果对精度没有太大要求时选择单端输入置00)

     第七位: 使能模拟输出,使能时置1 ,表示切换为DA(数字转模拟模式)

     第八位:无效位
                        
原文链接:https://blog.csdn.net/wcl501375/article/details/129626609

 芯片资料包代码

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/

#define DELAY_TIME	5

//
static void I2C_Delay(unsigned char n)
{
    do
    {
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();
        _nop_();_nop_();_nop_();_nop_();_nop_();		
    }
    while(n--);      	
}

//
void I2CStart(void)
{
    sda = 1;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 0;
	I2C_Delay(DELAY_TIME);
    scl = 0;    
}

//
void I2CStop(void)
{
    sda = 0;
    scl = 1;
	I2C_Delay(DELAY_TIME);
    sda = 1;
	I2C_Delay(DELAY_TIME);
}

//从IIC总线上发送数据
void I2CSendByte(unsigned char byt)
{
    unsigned char i;
	
    for(i=0; i<8; i++){
        scl = 0;
		I2C_Delay(DELAY_TIME);
        if(byt & 0x80){
            sda = 1;
        }
        else{
            sda = 0;
        }
		I2C_Delay(DELAY_TIME);
        scl = 1;
        byt <<= 1;
		I2C_Delay(DELAY_TIME);
    }
	
    scl = 0;  
}

//从IIC总线上接收数据
unsigned char I2CReceiveByte(void)
{
	unsigned char da;
	unsigned char i;
	for(i=0;i<8;i++){   
		scl = 1;
		I2C_Delay(DELAY_TIME);
		da <<= 1;
		if(sda) 
			da |= 0x01;
		scl = 0;
		I2C_Delay(DELAY_TIME);
	}
	return da;    
}

//等待应答
unsigned char I2CWaitAck(void)
{
	unsigned char ackbit;
	
    scl = 1;
	I2C_Delay(DELAY_TIME);
    ackbit = sda; 
    scl = 0;
	I2C_Delay(DELAY_TIME);
	
	return ackbit;
}

//发送应答
void I2CSendAck(unsigned char ackbit)
{
    scl = 0;
    sda = ackbit; 
	I2C_Delay(DELAY_TIME);
    scl = 1;
	I2C_Delay(DELAY_TIME);
    scl = 0; 
	sda = 1;
	I2C_Delay(DELAY_TIME);
}

自写代码

//函数名:ADC转换函数
//入口参数:要进行转换的通道控制位
//返回值:ADC转换的数值
//函数功能:对指定的通道进行ADC转换,函数返回转换的数值
unsigned char AD_Read(unsigned char channel_num_contrl)
{
	unsigned char temp;
	
	IIC_Start();//发送开启信号
	IIC_SendByte(0x90);//选择PCF8591芯片,确定写的模式
	IIC_WaitAck();//等待PCF8591反馈
	
	IIC_SendByte(channel_num_contrl);//确定要转换的通道(0X01光敏电阻或0X03电位器)顺便,使能DA转换(0X41或0X43)         存疑
	IIC_WaitAck();//等待PCF8591反馈	
	
	IIC_Start();//发送开启信号
	IIC_SendByte(0x91);//选择PCF8591芯片,确定读的模式
	IIC_WaitAck();//等待PCF8591反馈	
		
	temp = IIC_RecByte();//接收数据
	IIC_SendAck(1);//选择不应答
	IIC_Stop();//停止发送
	
	return temp;

}



//函数名:DAC转换函数
//入口参数:要进行转换的数值
//返回值:无
//函数功能:对入口参数要转换的DA数据进行转换
void DA_Write(unsigned char trans_dat)
{
	IIC_Start();//发送开启信号
	IIC_SendByte(0x90);//选择PCF8591芯片,确定写的模式
	IIC_WaitAck();//等待PCF8591反馈
	
	IIC_SendByte(0x41);//使能DA转换(随便写通道编号,不影响,主要的功能是使能DA)
	IIC_WaitAck();//等待PCF8591反馈		

	IIC_SendByte(trans_dat);//将待转换的数据发送出去
	IIC_WaitAck();//等待PCF8591反馈	
	IIC_Stop();//停止发送	

}

 main.c

/* 头文件声明区 */
#include <STC15F2K60S2.H>//单片机寄存器专用头文件
#include <Init.h>//初始化底层驱动专用头文件
#include <Led.h>//Led底层驱动专用头文件
#include <Key.h>//按键底层驱动专用头文件
#include <Seg.h>//数码管底层驱动专用头文件
#include "iic.h"//数模转换底层驱动头文件                    √

/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led显示数据存放数组
bit Seg_Disp_Mode;//数码管显示模式变量 0-电压显示界面 1-电压输出界面
float Voltage;//实时电压变量
float Voltage_Output;//实时电压输出变量
bit Output_Mode;//输出模式专用变量 0-2V 1-随AD输出
bit Seg_Flag = 1;//数码管功能标志位

/* 键盘处理函数 */
void Key_Proc()
{
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//键盘减速程序

	Key_Val = Key_Read();//实时读取键码值
	Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
	Key_Up = ~Key_Val & (Key_Old ^ Key_Val);//捕捉按键上降沿
	Key_Old = Key_Val;//辅助扫描变量

	switch(Key_Down)
	{
		case 19://显示界面切换按键
			Seg_Disp_Mode ^= 1;
		break;
		case 18://输出模式切换按键
			Output_Mode ^= 1;
		break;
		case 16://数码管功能按键
			Seg_Flag ^= 1;
		break;
	}
}

/* 信息处理函数 */
void Seg_Proc()
{
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管减速程序
	
	
	Voltage = AD_Read(0x43) / 51.0;//实时读取RB2电压数据
	if(Output_Mode == 0)//固定输出2V
		Voltage_Output = 2;
	else
		Voltage_Output = Voltage;
	
	if(Seg_Disp_Mode == 0)//处于电压显示界面
	{
		Seg_Buf[0] = 11;//U
		Seg_Buf[5] = (unsigned char)Voltage;
		Seg_Buf[6] = (unsigned int)(Voltage * 100) / 10 % 10;
		Seg_Buf[7] = (unsigned int)(Voltage * 100) % 10;
		Seg_Point[5] = 1;//点亮小数点
	}
	else//处于电压输出界面
	{
		Seg_Buf[0] = 12;//F
		Seg_Buf[5] = (unsigned char)Voltage_Output;
		Seg_Buf[6] = (unsigned int)(Voltage_Output * 100) / 10 % 10;
		Seg_Buf[7] = (unsigned int)(Voltage_Output * 100) % 10;
		Seg_Point[5] = 1;//点亮小数点		
	}
}

/* 其他显示函数 */
void Led_Proc()
{
	unsigned char i;
	DA_Write(Voltage_Output);//电压输出
	for(i=0;i<2;i++)
		ucLed[i] = (i == Seg_Disp_Mode);
	if(Voltage < 1.5 || (Voltage >= 2.5 && Voltage < 3.5))
		ucLed[2] = 0;
	else
		ucLed[2] = 1;
	ucLed[3] = Output_Mode;
}

/* 定时器0中断初始化函数 */
void Timer0Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;    //定时器中断0打开
	EA = 1;     //总中断打开
}

/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{  
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	if(++Seg_Pos == 8) Seg_Pos = 0;//数码管显示专用
	if(Seg_Flag == 1)
		Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	else
		Seg_Disp(Seg_Pos,10,0);
	Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}

/* Main */
void main()
{
	System_Init();
	Timer0Init();
	while (1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值