【51单片机入门记录】A/D、D/A转换器PCF859应用
目录
一、IIC初始化代码
二、开发板电路图
三、PCF8591读/写字节操作流程及相关函数
(1)PCF8591(AD)读操作流程及代码
(2)PCF8591(AD)写操作流程及代码
四、应用示例-显示电压值
一、IIC初始化代码
- 加载“iic.c文件”,主函数中添加iic.h头文件
- 调节软件延迟时长(全部扩大十倍即可)
- 编写PCF8591读写函数,并且在头文件中定义
- 编写用户用能函数
二、开发板电路图
(图源第十五届蓝桥杯电子赛资源包)

- 根据图以及前面所学的EEPROM存储器的位置,可知IIC总线上有两个设备,一个是PCF85191另一个是AT24C02 EEPROM存储器。
- AIN1(光敏电阻线路)、AIN3(活动变阻器、电压采集)

三、PCF8591读/写字节操作流程及相关函数
(1)PCF8591(AD)读操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写:0X90)
- 被控器做出应答后
- 主控器发出控制字节(写:)
- 被控器做出应答后
- 主控器发出停止信号
- 主控器发出起始信号
- 主控器发出寻址字节(读:0x91)
- 被控器做出应答后
- 主控器从被控器读出数据字节,主控器发出应答
- 主控器发出停止信号
unsigned char AD_read(unsigned char add)
{unsigned char dat;I2CStart();I2CSendByte(0X90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0X91);I2CWaitAck();dat=I2CReceiveByte();I2CSendAck(1);I2CStop();return dat;
}
(2)PCF8591(AD)写操作流程及代码
- 主控器发出起始信号
- 主控器发出寻址字节(写:0X90)
- 被控器做出应答后
- 主控器发出控制字节(写)
- 被控器做出应答后
- 主控器发出DA输出数据字节(写)
- 被控器做出应答后
- 主控器发出停止信号
void AD_write(unsigned char dat)
{I2CStart();I2CSendByte(0X90);I2CWaitAck();I2CSendByte(0X40);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();}
四、应用示例-显示电压值
//iic.c
#include <STC15F2K60S2.H>
#include<intrins.h>
#define DELAY_TIME 50//总线引脚定义
sbit sda = P2^1;
sbit scl = P2^0; //
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);
}//
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;
}//
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);
}unsigned char AD_read(unsigned char add)
{unsigned char dat;I2CStart();I2CSendByte(0X90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStop();I2CStart();I2CSendByte(0X91);I2CWaitAck();dat=I2CReceiveByte();I2CSendAck(1);I2CStop();return dat;}
void AD_write(unsigned char dat)
{I2CStart();I2CSendByte(0X90);I2CWaitAck();I2CSendByte(0X40);I2CWaitAck();I2CSendByte(dat);I2CWaitAck();I2CStop();}
//IIC.h
#ifndef _IIC_H
#define _IIC_H
//
static void I2C_Delay(unsigned char n);//
void I2CStart(void);//
void I2CStop(void);//
void I2CSendByte(unsigned char byt);//
unsigned char I2CReceiveByte(void);//
unsigned char I2CWaitAck(void);//
void I2CSendAck(unsigned char ackbit);
//
unsigned char AD_read(unsigned char add);
void AD_write(unsigned char dat);#endif
//main.c
#include <STC15F2K60S2.H>
#include<intrins.h>
#include<IIC.h>#define uchar unsigned char
#define uint unsigned intunsigned char LED_Bit=0XFF;
unsigned char Actuator_Bit=0X00;#define LEDx_ON(n) { LED_Bit&=_crol_(0XFE,n-1); P0=LED_Bit; P2|=0X80; P2&=0X9F; P2&=0X1F;}
#define LEDx_OFF(n) { LED_Bit|=_crol_(0X01,n-1); P0=LED_Bit; P2|=0X80; P2&=0X9F; P2&=0X1F;}#define Buzzer_ON Actuator_Bit|=0x40; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F;
#define Buzzer_OFF Actuator_Bit&=0XBF; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F;
#define Relay_ON Actuator_Bit|=0x10; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F;
#define Relay_OFF Actuator_Bit&=0XEF; P0=Actuator_Bit; P2|=0XA0; P2&=0XBF; P2&=0X1F;unsigned char code tab[]= {0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,\0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,\0XBF,0XFF};
unsigned char KEY_Value = 0 ;
unsigned char DigCom=0;
unsigned char DigBuf[8] = {10,10,10,10,10,10,10,10};unsigned char LED = 1 ;
unsigned int LED_tt =0;
bit LED_Ref = 0 ;unsigned int SEG_tt =0; //定义一个数码管计数时间标识位
bit SEG_Ref = 0 ; //定义一个数码管刷新标识位
bit SEG_Run = 0 ; //定义一个控制数码管运行标识位
unsigned int Num = 999 ;unsigned char Open;unsigned char EEPROM_Write[8] = {2,3,4,5,6,7,8,9};
unsigned char EEPROM_Read[8] = {0,0,0,0,0,0,0,0};unsigned int AD_VALUE=0;
unsigned int AD_tt =0;
bit AD_Ref =0;void ALL_Init(void);
void Delay_MS(unsigned int MS);
void KeyScan(void);
void ArrKeyScan(void);
void Timer0Init(void); //1毫秒@11.0592MHzvoid main(void)
{ALL_Init();Timer0Init();EA=1;ET0=1;while(1){if(AD_Ref == 1){AD_Ref = 0 ;AD_VALUE = AD_read(0X03);AD_write(AD_VALUE);AD_VALUE = AD_VALUE * 1.96;DigBuf[2]=21;DigBuf[3]=21;DigBuf[4]=21;DigBuf[5]=AD_VALUE/100 + 10; DigBuf[6]=AD_VALUE%100/10;DigBuf[7]=AD_VALUE%10; }KeyScan();if(KEY_Value==7){KEY_Value=0;SEG_Run = 1 ;}if(KEY_Value==6){KEY_Value=0;SEG_Run = 0 ;}if(KEY_Value==5){KEY_Value=0;LEDx_ON(1);Buzzer_ON;}if(KEY_Value==4){KEY_Value=0;LEDx_OFF(1);Buzzer_OFF;} }
}void KeyScan(void)
{if(P30==0){Delay_MS(10);if(P30==0)KEY_Value = 7 ; while(!P30);}else if(P31==0){Delay_MS(10);if(P31==0)KEY_Value = 6 ; while(!P31);} else if(P32==0){Delay_MS(10);if(P32==0)KEY_Value = 5 ; while(!P32);} else if(P33==0){Delay_MS(10);if(P33==0)KEY_Value = 4 ; while(!P33);}
}void Timer0(void) interrupt 1
{P0=0X00;P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器 P0=tab[DigBuf[DigCom]]; P2|=0XE0; // P2=P2|0XE0; XXXX XXXX | 1110 0000 = 111X XXXXP2&=0XFF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器P0=(0X01<<DigCom); //然后选中第一个数码管P2|=0XC0; // P2=P2|0XC0; XXXX XXXX | 1100 0000 = 11XX XXXXP2&=0XDF; // P2=P2&0XDF; 11XX XXXX & 1101 1111 = 110X XXXX P2&=0X1F; //关闭所有的74HC573锁存器if(++DigCom == 8)DigCom = 0 ;LED_tt++;if(LED_tt == 999) {LED_tt = 0 ; LED_Ref = 1 ;}if(++SEG_tt==1000){SEG_tt=0;SEG_Ref=1;}if(++AD_tt==500){AD_tt=0;AD_Ref=1;}
// XXX_tt++;
// if(++XXX_tt==NNN){XXX_tt=0;XXX_Ref=1;}
}void Timer0Init(void) //1毫秒@11.0592MHz
{AUXR |= 0x80; //定时器时钟1T模式TMOD &= 0xF0; //设置定时器模式TL0 = 0xCD; //设置定时初始值TH0 = 0xD4; //设置定时初始值TF0 = 0; //清除TF0标志TR0 = 1; //定时器0开始计时
}void Delay_MS(unsigned int MS)
{unsigned i,j;for(i=0;i<MS;i++)for(j=853;j>0;j--); //STC15单片机设置为853; STC8H单片机修改为1109;STC32G单片机修改为427;
}void ALL_Init(void)
{P0 =0X00; //先设置关闭蜂鸣器继电器的P0输出值(全关)P2|=0XA0; // 将P27 P25 设置为1 其他位保持不变P2&=0XBF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0XFF; //先设置关闭所有的LED的P0输出值(全关)P2|=0X80; // 将P27设置为1 其他位保持不变P2&=0X9F; // 将P26 P25设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器P0 =0X00; //先设置选择数码管位选的P0输出值(全不选)P2|=0XC0; // 将P27 P26 设置为1 其他位保持不变P2&=0XDF; // 将P26设置为0 其他位保持不变P2&=0X1F; //关闭所有的74HC573锁存器
}
相关文章:
【51单片机入门记录】A/D、D/A转换器PCF859应用
目录 一、IIC初始化代码 二、开发板电路图 三、PCF8591读/写字节操作流程及相关函数 (1)PCF8591(AD)读操作流程及代码 (2)PCF8591(AD)写操作流程及代码 四、应用示例-显示电压…...
设计模式(13):模板方法模式
场景: 实现一个功能时,整体步骤很固定,但是,某些部分易变。易变部分可以抽象出来,供子类实现。 开发中常见的场景 非常繁琐,各个框架,类库中都有它的影子,比如常见的有࿱…...
公众号申请上限怎么提升
一般可以申请多少个公众号?众所周知,在2013年前后,公众号申请是不限制数量的,后来企业开始限制申请50个,直到2018年的11月tx又发布,其中个人主体可申请公众号由2个调整为1个,企业主体由50个调整…...
【算法刷题day16】Leetcode:104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数
104.二叉树的最大深度 (优先掌握递归) 文档链接:[代码随想录] 题目链接:104.二叉树的最大深度 (优先掌握递归) 状态:ok 题目: 给定一个二叉树 root ,返回其最大深度。 二…...
电商技术揭秘一:电商架构设计与核心技术
文章目录 引言一、电商平台架构概述1.1 架构设计原则与架构类型选择1.2 传统电商平台架构与现代化架构趋势分析 二、高并发处理与负载均衡2.1 高并发访问特点分析与挑战2.2 负载均衡原理与算法选择 三、分布式数据库与缓存技术3.1 分布式数据库设计与一致性考量3.2 缓存策略与缓…...
Ubuntu 自启动应用程序的方法
1、自启动的方法 自启动应用程序可以在/etc/rc.local文件中调用脚本来启动应用程序,另外也可以自行编写一个服务来启动应用程序。这两种方法其实都是一种方法即使用服务来启动一个应用程序。rc.local脚本本身也是被一个rc.local的服务来调用的。如下图,可…...
Star GAN论文解析
论文地址:https://arxiv.org/pdf/1912.01865v1.pdf https://openaccess.thecvf.com/content_cvpr_2018/papers/Choi_StarGAN_Unified_Generative_CVPR_2018_paper.pdf 源码:stargan项目实战及源码解读-CSDN博客 1. 概述 在传统方法中&#x…...
全网最强JavaWeb笔记 | 万字长文爆肝JavaWeb开发——day06_数据库-MySQL-02
万字长文爆肝黑马程序员2023最新版JavaWeb教程。这套教程打破常规,不再局限于过时的老套JavaWeb技术,而是与时俱进,运用的都是企业中流行的前沿技术。笔者认真跟着这个教程,再一次认真学习一遍JavaWeb教程,温故而知新&…...
数据结构day2--双向链表
双向链表: 即可以从头遍历到尾部和从尾部遍历到头部的链表,每个结点包括两个链域:前驱指针域和后继指针域,所以比起单向链表,其可以在任意一个结点访问前后两个结点 关于双向链表的一个完整步骤为: 创建一个表头结构…...
蓝桥杯单片机真题实践篇
这里就不完全写思路过程代码什么的,这一篇文章就写我在训练真题中遇到的过程。 (呜呜呜,时间不够辣,能做多少算多少吧....) 十三届省赛题 问题1:数码管的数字消影不明显 (参考:蓝…...
前端pdf.js将pdf转为图片,尤其适合电子发票打印
写这个的原因就是打电子发票不方便,这个代码是纯js不需要后端服务直接将两张电子发票的pdf转为两张图片渲染到一张A4纸上面(完全不浪费,发票也不会变大),自动完成打印分页,点击打印即可。亲测可用所有电子发…...
第四百四十三回
文章目录 1. 概念介绍2. 思路与方法2.1 整体思路2.2 使用方法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义Action菜单"相关的内容,本章回中将介绍如何获取屏幕相关参数.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…...
一分钟快速用上号称“音乐版ChatGPT”的suno AI,适合普通人的超简单教程!
随着AI的应用变广,各类AI程序已逐渐普及。AI已逐渐深入到人们的工作生活方方面面。而AI涉及的行业也越来越多,从最初的写作,到医疗教育,再到现在的音乐。 Suno是一个专业高质量的AI歌曲和音乐创作平台,用户只需输入简…...
干货!一文读懂:位像素海外仓系统的分销功能
随着跨境电商的蓬勃发展,海外仓系统的重要性日益凸显,成为企业在激烈市场竞争中脱颖而出的关键。当谈及海外仓系统的拓展功能,特别是其中的分销功能,正逐渐成为卖家们不可或缺的工具。 那么,这个神奇的分销功能究竟是…...
【洛谷】P1449 后缀表达式
题目描述 所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。 本题中运算符仅包含 -*…...
【MySQL】聚合函数和分组聚合
👦个人主页:Weraphael ✍🏻作者简介:目前学习计网、mysql和算法 ✈️专栏:MySQL学习 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬…...
RDD算子(四)、血缘关系、持久化
1. foreach 分布式遍历每一个元素,调用指定函数 val rdd sc.makeRDD(List(1, 2, 3, 4)) rdd.foreach(println) 结果是随机的,因为foreach是在每一个Executor端并发执行,所以顺序是不确定的。如果采集collect之后再调用foreach打印…...
51之定时器与中断系统
目录 1.定时器与中断系统简介 1.1中断系统 1.2定时器 1.2.1定时器简介 1.2.2定时器大致原理及其配置 1.2.3定时器所需的所有配置总介 2.定时器0实现LED闪烁 3.使用软件生成定时器初始化程序 1.定时器与中断系统简介 1.1中断系统 首先,我们需要来了解一下什么…...
C语言中的内存函数
相比于内存函数,字符串函数和字符函数是对字符串和字符进行操作,内存函数是对内存进行操的。下面跟大家分享我学到的几个内存函数。 memcpy函数 void* memcpy(void* dest, const void* sour, size_t num); dest是目标地址,sour要拷贝的源地…...
JS继承与原型、原型链
在 JavaScript 中,继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及组合继承等几种常见的继承方式,并提供相应的示例代码,并分析它们的特点、优缺点以及适用场景。 在开始讲解 JavaScript 的继承方式之…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
Linux 下 DMA 内存映射浅析
序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程,可以参考这篇文章,我觉得写的非常…...
聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
