2026/4/7 3:33:23
网站建设
项目流程
新手怎么做网站,公司网络维护服务,装修房子找哪家装修公司好,天津怎么建立企业网站**
蓝桥杯单片机备赛指南第十三讲#xff1a;IIC 总线与PCF8591 AD DA 转换
**
1. IIC 总线与PCF8591 硬件原理
1.1 IIC 通信协议(软件模拟)
IIC (Inter-Integrated Circuit) 是一种双线串行总线。SCL (P2.0)#xff1a;时钟线。SDA (P2.1)#xff1a;数据线。时序核心(死记…**蓝桥杯单片机备赛指南第十三讲IIC 总线与PCF8591 AD DA 转换**1. IIC 总线与PCF8591 硬件原理1.1 IIC 通信协议(软件模拟)IIC (Inter-Integrated Circuit) 是一种双线串行总线。SCL (P2.0)时钟线。SDA (P2.1)数据线。时序核心(死记硬背)起始(Start)SCL 高期间SDA 下降沿。停止(Stop)SCL 高期间SDA 上升沿。应答(ACK)发送8 位后第9 个时钟周期SDA 被拉低。1.2 PCF8591 芯片详解设备地址写地址0x90读地址0x91。控制字(Control Byte)通道选择Bit 0-1 (00AIN0, 01AIN1, 10AIN2, 11AIN3)。DA 使能Bit 6 (1开启模拟输出)。常用控制字0x01: 读光敏电阻(AIN1)。0x03: 读电位器Rb2 (AIN3)。0x40: 仅启用DAC 输出。2. 进阶底层驱动模块2.1 基础外设驱动(LED.c更新版)重点增加了Beep和Relay且所有函数均采用static变量 位运算确保互不干扰。#includeLED.h// LED 单灯控制 (非破坏性)voidLED_Disp(unsignedcharaddr,bit enable){staticunsignedcharTemp0x00;staticunsignedcharTemp_Old0xFF;if(enable)Temp|(0x01addr);elseTemp~(0x01addr);if(Temp!Temp_Old){P0~Temp;// 共阳极取反输出P2P20x1F|0x80;// 打开 Y4 (LED)P20x1F;// 锁存Temp_OldTemp;}}// 蜂鸣器控制 (非破坏性)voidBeep(bit enable){staticunsignedcharTemp0x00;// 0x00 表示初始关闭状态 (假设 ULN2003 输入0为关)staticunsignedcharTemp_Old0xFF;// 蜂鸣器通常接在 P0.6 (0x40)if(enable)Temp|0x40;// 置 1 开启elseTemp~0x40;// 置 0 关闭if(Temp!Temp_Old){P0Temp;// 直接输出 (ULN2003 驱动)P2P20x1F|0xA0;// 打开 Y5 (蜂鸣器/继电器)P20x1F;Temp_OldTemp;}}// 继电器控制 (非破坏性)voidRelay(bit flag){staticunsignedchartemp0x00;staticunsignedchartemp_old0xff;// 继电器通常接在 P0.4 (0x10)if(flag)temp|0x10;elsetemp~0x10;if(temp!temp_old){P0temp;P2P20x1F|0xA0;// 打开 Y5P20x1F;temp_oldtemp;}}2.2 IIC 与PCF8591 读写(iic.c补全)官方提供的代码包通常只有基础时序必须熟练默写以下两个函数。#includeiic.h#includeintrins.h// ... (I2CStart, I2CStop, I2CSendByte 等基础时序略参考官方文件) ...// 1. PCF8591 A/D 读取函数 // addr: 通道号 (0x01 光敏, 0x03 电位器)unsignedcharAd_Read(unsignedcharaddr){unsignedchartemp;I2CStart();I2CSendByte(0x90);// 写设备地址I2CWaitAck();I2CSendByte(addr);// 写控制字 (选择通道)I2CWaitAck();I2CStart();// 重新起始I2CSendByte(0x91);// 读设备地址I2CWaitAck();tempI2CReceiveByte();// 读取数据I2CSendAck(1);// 发送非应答 (1)结束读取I2CStop();returntemp;}// 2. PCF8591 D/A 写入函数 // dat: 输出电压对应的数字量 (0~255)voidDa_Write(unsignedchardat){I2CStart();I2CSendByte(0x90);// 写设备地址I2CWaitAck();I2CSendByte(0x40);// 写控制字 (0x40 启用 DAC)I2CWaitAck();I2CSendByte(dat);// 发送 DAC 数据I2CWaitAck();I2CStop();}3. 功能设计要求(电压采集装置)基于**《蓝桥杯模块训练- PCF8591.pdf》**原题整理。3.1 数码管显示系统包含两个界面通过S4 切换。电压显示界面(界面U)内容显示电位器RB2 (AIN3) 的实时电压。格式U 3.41(保留两位小数)。细节提示符’U’ 在第1 位数据在6-8 位中间熄灭。电压输出界面(界面F)内容显示当前DAC 输出端的电压值。格式F 2.50。细节提示符’F’ 在第1 位。3.2 按键逻辑S4 (界面切换)在U(显示) 和F(输出) 界面间循环。S5 (模式切换)切换DAC 的输出模式。模式1 (跟随)输出电压 RB2 输入电压。模式2 (固定)输出电压固定为2.0V。S6 (LED 开关)开启或关闭LED 指示功能。关闭时所有LED 熄灭。3.3 LED 指示逻辑(修正版)根据PDF 任务书要求L1指示当前在电压显示界面。L2指示当前在电压输出界面。L3当测量电压V3.5VV 3.5VV3.5V或2.5VV1.5V2.5VV 1.5V2.5VV1.5V时点亮。L4DAC 输出固定电压2.0V时L4 熄灭DAC 输出电压跟 随 RB2 电位器输出电压变化时L4 点亮。S6 限制若S6 关闭了指示功能L1-L4 必须全部熄灭。4. 核心代码解答(main.c)#includeSTC15F2K60S2.H#includeInit.h#includeKey.h#includeLED.h#includeSeg.h#includeiic.h// 变量声明 typedefunsignedcharu8;typedefunsignedintu16;u8 Key_Slow_Down0;u16 Seg_Slow_Down0;u8 LED_Seg_Pos0;// 数码管/LED 扫描指针// 显存与状态u8 Seg_Buf[8]{10,10,10,10,10,10,10,10};u8 Seg_Point[8]{0,0,0,0,0,0,0,0};u8 LED_Buf[8]{0,0,0,0,0,0,0,0};// LED 状态缓存 (1亮 0灭)u8 Key_Val,Key_Old,Key_Down,Key_Up;// 业务标志位bit Seg_Mode0;// 0:电压显示界面(U), 1:电压输出界面(F)bit Mode1_Flag0;// DAC模式: 0固定2.0V, 1跟随RB2bit LED_Flag1;// LED总开关: 1开, 0关 (默认开)bit Seg_Flag1;// 数码管总开关 (题目未要求按键控制保持常开)floatVoltage0;// 测量电压 (RB2)floatOutput_Voltage2.0;// DAC 输出电压// 按键逻辑 voidKey_Proc(){if(Key_Slow_Down)return;Key_Slow_Down1;Key_ValKey_Read();Key_DownKey_Val(Key_Val^Key_Old);Key_OldKey_Val;switch(Key_Down){case4:// S4: 界面切换Seg_Mode^1;break;case5:// S5: DAC 输出模式切换Mode1_Flag^1;break;case6:// S6: LED 功能开关LED_Flag^1;break;}}// 数据处理与显示 voidSeg_Proc(){u8 i;if(Seg_Slow_Down)return;Seg_Slow_Down1;// 1. 读取 A/D (RB2 - AIN3)// 算法: Val / 255.0 * 5.0 Val / 51.0VoltageAd_Read(0x03)/51.0;// 2. 处理 D/A 输出if(Mode1_Flag)Output_VoltageVoltage;// 跟随模式elseOutput_Voltage2.0;// 固定模式Da_Write((u8)(Output_Voltage*51.0));// 写入 DAC// 3. 数码管显示更新if(Seg_Flag){// 熄灭无关位Seg_Buf[1]Seg_Buf[2]Seg_Buf[3]Seg_Buf[4]10;// 设置小数点 (第5位点亮对应 xxx.xx)for(i0;i8;i)Seg_Point[i]0;Seg_Point[5]1;if(Seg_Mode0)// 界面 U: 显示测量电压{Seg_Buf[0]17;// U (假设字模 17)Seg_Buf[5](u8)Voltage;// 个位Seg_Buf[6](u8)(Voltage*10)%10;// 十分位Seg_Buf[7](u16)(Voltage*100)%10;// 百分位}else// 界面 F: 显示输出电压{Seg_Buf[0]16;// F (假设字模 16)Seg_Buf[5](u8)Output_Voltage;Seg_Buf[6](u8)(Output_Voltage*10)%10;Seg_Buf[7](u16)(Output_Voltage*100)%10;}}else{for(i0;i8;i)Seg_Buf[i]10;}}// LED 逻辑控制 voidLED_Proc(){u8 i;if(LED_Flag)// 总开关打开{// L1/L2: 界面指示 (互斥)LED_Buf[0]!Seg_Mode;// Mode0(U) - L1亮LED_Buf[1]Seg_Mode;// Mode1(F) - L2亮// L3/L4/L5: 电压范围指示 (基于测量电压 Voltage)LED_Buf[2](Voltage1.5);LED_Buf[3](Voltage1.5Voltage2.5);LED_Buf[4](Voltage2.5);// L6-L8: 熄灭LED_Buf[5]LED_Buf[6]LED_Buf[7]0;}else// 总开关关闭{for(i0;i8;i)LED_Buf[i]0;}}// 定时器中断 (驱动层) voidTimer0_Server()interrupt1{// ... 重装载代码 (1ms) ...if(Key_Slow_Down10)Key_Slow_Down0;if(Seg_Slow_Down200)Seg_Slow_Down0;// 硬件扫描if(LED_Seg_Pos8)LED_Seg_Pos0;// 驱动数码管Seg_Disp(LED_Seg_Pos,Seg_Buf[LED_Seg_Pos],Seg_Point[LED_Seg_Pos]);// 驱动 LED (调用更新后的非破坏性驱动)LED_Disp(LED_Seg_Pos,LED_Buf[LED_Seg_Pos]);}voidmain(){// System_Init(); // 需包含初始化// Timer0_Init(); // 需包含定时器初始化while(1){Key_Proc();Seg_Proc();LED_Proc();}}5. 总结速查表(Cheat Sheet)模块关键代码/公式备注电压计算V Val / 51.0255对应5V系数为51DAC 输出Val V * 51.0逆运算写入PCF8591通道地址0x03(电位器),0x01(光敏)一定要看电路图确认DAC 控制字0x40写数据前必须发送此控制字LED 逻辑LED_Buf[0] !Seg_Mode利用逻辑非运算实现互斥指示非破坏驱动P2 0x1F0x80