STM32的I2C通信实例pcf8591(AD/DA)原创干货_stm32i2c的例程_别把我的消息带回家乡的博客-程序员宅基地

技术标签: stm32  嵌入式  单片机  

 

 

 

本程序是stm32f103 接pcf8591AD/DA板(YL-PCF8591),I2C通信,I2C通信用的是模拟I2C,不是STM32 自带的硬件I2C外设。实践检验很稳定。SCL接口用PB6,SDA用PB7,与STM32自带的硬件I2C接口针脚是一样的,这是巧合,你也可以随便定义成别Pin针脚。关于GPIO设置,最后有解释。

  1. Pcf8591地址写是0x90,读是0x91,
  2. AIN0地址是0x40 -------AIN3地址是0x43,注意AOUT地址也是0x40

写比较简单看下面程序:下面是DA(数/模转换主程序)主要用写函数。

u8 DACconversion(u8 sla,u8 c,  u8 Val)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

   ack();                      //8591应答

   SendByte(c);              //发送控制字节

    ack();                  //8591应答

   SendByte(Val);            //发送DAC的数值 

    ack();                       //8591应答

   Stop_I2c();               //结束总线

   return(1);

}

启动:SCL高电平中间SDA高变低,紧接着SCL变低,

停止:SCL低电平变高电平后,SDA低变高,

Ack应答是主机释放SDA后,从机(PCF8591把SDA拉低)。

DA转换的过程是,先开始,发送从机地址90,从机应答后,发送寄存器地址,40代表AIN0(AOUT也是40 ),从机应答后,发送写入的数据,从机应答,结束传输。

是不是很简单?DOUT输出电压范围(0-255对应0-3.3v )输出接口接有蓝色LED,输出电压大于2V,LED 开始亮起了,电压越高,越亮。

----------------------------------------------------------------------------------------------/

下面说明读数据程序,稍微复杂一点。

u8 ADCconversion(u8 sla,u8 c)

{

       u8 d;

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址0x90

   ack();                    //从机接收后应达

   SendByte(c);              //发送控制字节0x43

    ack();                   //从机接收后应达

Stop_I2c();               //停止总线

//------------------------------------------------

Start_I2c();              //启动总线

SendByte(sla+1);           //发送读AIN3指令

ack();                    //从机应对不能少

   d=RcvByte();            //发送DAC的数值 

   Ack_I2c(0);             //主机接收后应答不能少否则不稳定

   Stop_I2c();               //结束总线

   return(d);

}

我们读取第4个AIN口因为接有可变电阻,可以直观看到输入数据变化,AIN3地址是0x43(第一个是光敏)(第二个是热敏)(第三个是直通)

下面分析程序,下面是AD转换,接收第四个AIN的电压信号,0-3.3V对应数字0-255:

AD起始的程序和DA相同,开始-发送从站地址90,从站应答,发送控制字43,从站应答,之后的程序就不一样的,停止

再次开始,发送读指令91,从站应答,主机读8位数据,读到后主机应答0,表示接受到,最后停止传输。(注意没有这个主机接收应答,接收到数据就乱了在数据和255之间乱跳)。

可以看到Ad转换开始停止两次。特别注意,主机接收到数据后,主机回复Ack(0)。不是从机。

///------------------------------------------------------------------------------------------------///

最后说一下关于:IIC的GPIO设置。

void GPIO_init(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

 

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

     

      GPIO_InitStructure.GPIO_Pin = SCL_Pin | SDA_Pin;     /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

      GPIO_Init(GPIOB, &GPIO_InitStructure);

 

      SCL_SET(1);

      flash();

      SDA_SET(1);

      flash();

}

这是GPIO初始化程序,可见GPIO设置为推挽输出,这样I2C的波形用示波器观察就是正经的方波,但是推挽输出只能写数据,I2C读数据的时候必须用in_floating,见下面:

void SDA_IO_IN(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

      GPIO_InitStructure.GPIO_Pin = SDA_Pin;  /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;      

      GPIO_Init(GPIOB, &GPIO_InitStructure);

}

 

void SDA_IO_OUT(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

      GPIO_InitStructure.GPIO_Pin = SDA_Pin;  /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

      GPIO_Init(GPIOB, &GPIO_InitStructure);

}

上面程序可见,SCL(PB6)是主机主导,所以一般设为PP不变(推挽输出),SDA因为读到时候是从机发数据,所以对于SDA(PB7)脚,在写数据时候设置成PP(推挽输出),在读入数据时设置成in_floating。这样的波形很漂亮的方波,用示波器观察很爽,逻辑清晰可见。

也有的程序SCL SDA 都设置成OD(开漏输出)不变,这就不用设置变来变去,也是可以的,就是观察波形的时候,波形底部是方波(因为漏极有场效应管通断),波形上部就是三角锯齿波了,(因为没有上场效应管控制,高电位是靠上拉电阻)。这种设置也是可以用,还简单,就是不利于用示波器观察。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41795958/article/details/113472258

智能推荐

SpringMVC学习杂记_小帅吖的博客-程序员宅基地

SpringMVC学习笔记1.Mybatis1.MyBatis 是一款优秀的持久层框架2.完成持久化工作的代码块 . ----> dao层 【DAO (Data Access Object) 数据访问对象】3.Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .4.MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射5.MyBatis的优点1.mybatis不会对应用程序或者数据库的现

2020年度“全球酒店集团225强”排名公布,首旅如家再进榜单前十-程序员宅基地

上海2021年8月4日 /美通社/ -- 近日,酒店业国际权威杂志《HOTELS》公布2020年度“全球酒店集团225强” (HOTELS 225)排名,首旅如家酒店集团凭借432,453..._hotel杂志酒店排名

golang package path_goland package path-程序员宅基地

package filepathfilepath包实现了兼容各操作系统的文件路径的实用操作函数。import “path/filepath”func Join(elem ...string) stringJoin函数可以将任意数量的路径元素放入一个单一路径里,会根据需要添加路径分隔符。结果是经过简化的,所有的空字符串元素会被忽略。package mainimport ( "fm..._goland package path

怎么用指令打开服务器的文件,如何用命令行打开远程服务器-程序员宅基地

如何用命令行打开远程服务器 内容精选换一换修改/etc/slog.conf配置文件中zip_switch配置项的值为0,修改完成后,重启slogd、IDE-daemon-host进程,详细内容请参见如何重启slogd进程。登录host侧服务器,进入/var/dlog目录,使用cat命令查看日志文件内容信息。日志下载、删除等方法,类似Linux操作系统服务器上下载、删除文件的方法。修改/etc/sl..._怎么在命令提示符里的服务器里打开项目

详解如何使用gulp实现项目在浏览器中的自动刷新_gulp 自动刷新页面-程序员宅基地

情况描述:我们很容易遇到这样一种情况:   我们并不是一开始就规划好了整个项目,比如可能接手别人的项目或者工程已经手动创建好了,现在要想利用gulp来实现浏览器自动刷新,那么如何做呢?   其实非常简单,本篇文章将详细介绍实现方法和其中可能遇到的一些坑。    假设你已经使用npm全局安装了gulp,那么具体方法如下:一、创建gulpfile.js文件  首先在项目根目录创建g_gulp 自动刷新页面

亲测成功解决Typora旧版本无法使用提示需要更新的问题_typora老版本强制更新-程序员宅基地

解决Typora旧版本无法使用提示需要更新的问题_typora老版本强制更新

随便推点

Ubuntu亲测简单有效的共享文件夹(Shared Folders)自动挂载方法 (转载)_ub share folders-程序员宅基地

Ubuntu装过不知多少次,共享问题一直没怎么解决,最近要重新安装Ubuntu16.04,正好记录一次。亲测可用!1. 安装依赖库Ctrl+Alt+T 打开终端,输入以下命令://确保依赖库已安装sudo apt install linux-headers-$(uname -r) build-essential dkms//安装后重启reboot2. 安装Virtualbox虚拟机增强套件//确保当前用户有访问共享文件夹的权限sudo adduser $USER vboxsf/_ub share folders

SignalR,前端js代码,再次封装_slgrjjs-程序员宅基地

SignalrTools.js//需要按顺序引入的文件jquery-1.6.4.min.js,jquery.signalR-2.3.0.js,signalr/hubs,SignalrTools.js//SRTools.oFn = { welcome: function () { alert("欢迎连接到技术员") },sorry: function () { alert("技术员正忙") }}..._slgrjjs

torch.scatter_harry_tea的博客-程序员宅基地

本文目录一、函数简介二、二维举例三、详解执行过程1. 第一步2. 第二步3. 第三步4. 问题一、函数简介torch.scatter(input, dim, index, src)dim ([int]) – the axis along which to indexindex (LongTensor) – the indices of elements to scatter, can be either empty or of the same dimensionality as src. Whe_torch.scatter

Tensorflow: failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED-程序员宅基地

Maybe the following command helps:sudo rm -rf .nv/Good luck.

elementui tree懒加载刷新问题-程序员宅基地

elementui el-tree懒加载刷新问题el-tree懒加载解决思路el-tree懒加载先说一哈问题,本人的项目中点击不同的选项加载不同的树,在用elementUi el-tree懒加载的时候,发现只加载一次,即使数据刷新了,但是tree就是不刷新!在这分享一下一个简单快捷的方法让它刷新!解决思路说明一下,我的项目中根节点和子节点的接口不一样,在这贴上加载树的方法,其他的不贴了。...

LeetCode Top100之236, 239,279,297,300,322题_leetcode top300-程序员宅基地

236. 二叉树的最近公共祖先① 题目描述中文描述:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/② 递归从根节点开始,如果当前节点为p或q,将其标记为1(表示true);否则为0,表示false。遍历左分支、右分支,如果在左分支或右分支中找到节点p或q,将其标记为1(表示true);否..._leetcode top300