STM32 基础知识(探索者开发板)--146讲 IIC

IIC特点:

        同步串行半双工通信总线

IIC有一个弱上拉电阻,在主机和从机都没有传输数据下拉时,总线会自动上拉

SCL在低电平期间,改变SDA的值来上传数据,方便SCL电平上升时进行数据读取

SCL在高电平期间,不能改变SDA的值,若改变,SDA高到低为起始信号,低到高为终止信号

IIC配置步骤

1.使能SCL和SDA对应时钟        _HAL_RCC_GPIOB_CLK_ENABLE()

2.设置GPIO工作模式                HAL_GPIO_Init()

3.编写基本信号                起始send ack 停止send nak 应答wait ack

4.编写读和写函数                  iic_read_byte   iic_send_byte

软件驱动外设步骤

1.初始化IIC接口

2.编写写入/读取一个字节数据的函数

3.编写连续读和连续写函数

iic代码

//myiic.c#include "./BSP/IIC/myiic.h"
#include "./SYSTEM/delay/delay.h"//初始化IIC
void iic_init(void)
{GPIO_InitTypeDef gpio_init_struct;IIC_SCL_GPIO_CLK_ENABLE();  /* SCL引脚时钟使能 */IIC_SDA_GPIO_CLK_ENABLE();  /* SDA引脚时钟使能 */gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;        /* 推挽输出 */gpio_init_struct.Pull = GPIO_PULLUP;                /* 上拉 */gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 快速 */HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);/* SCL */gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;            gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;        /* 开漏输出 */HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);/* SDA *//* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */iic_stop();     /* 停止总线上所有设备 */
}//IIC延时函数,给芯片反应时间
static void iic_delay(void)
{delay_us(2);    /* 2us的延时, 读写速度在250Khz以内 */
}//编写时序,产生IIC起始信号
void iic_start(void)
{IIC_SDA(1);IIC_SCL(1);iic_delay();IIC_SDA(0);     /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */iic_delay();IIC_SCL(0);     /* 下拉I2C总线,准备发送或接收数据 */iic_delay();
}//编写时序,产生IIC结束信号
void iic_stop(void)
{IIC_SDA(0);     /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */iic_delay();IIC_SCL(1);iic_delay();IIC_SDA(1);     /* 发送I2C总线结束信号 */iic_delay();
}//接收应答信号,1为接收失败,0为接收成功
uint8_t iic_wait_ack(void)
{uint8_t waittime = 0;uint8_t rack = 0;IIC_SDA(1);     /* 主机释放SDA线(此时外部器件可以拉低SDA线) */iic_delay();IIC_SCL(1);     /* SCL=1, 此时从机可以返回ACK应答信号 */iic_delay();while (IIC_READ_SDA)    /* 等待应答 */{waittime++;if (waittime > 250){iic_stop();rack = 1;break;}}IIC_SCL(0);     /* SCL=0, 结束ACK检查 */iic_delay();return rack;
}/*** @brief       从机产生ACK应答*/
void iic_ack(void)
{IIC_SDA(0);     /* SCL = 1 时 SDA = 0,表示应答 */iic_delay();IIC_SCL(1);iic_delay();IIC_SCL(0);     /* 产生下一个时钟 */iic_delay();IIC_SDA(1);     /* 释放SDA线 */iic_delay();
}/*** @brief       不产生ACK应答*/
void iic_nack(void)
{IIC_SDA(1);     /* SCL = 1  时 SDA = 1,表示不应答 */iic_delay();IIC_SCL(1);iic_delay();IIC_SCL(0);     /* 产生下一个时钟 */iic_delay();
}/*** @brief       IIC发送一个字节 
*/
void iic_send_byte(uint8_t data)
{uint8_t t;for (t = 0; t < 8; t++){IIC_SDA(data & (0x80 >> t));    /* 高位先发送,发完后右移 */iic_delay();IIC_SCL(1);iic_delay();IIC_SCL(0);}IIC_SDA(1);         /* 发送完成, 主机释放SDA线 */
}/*** @brief       IIC读取一个字节* @param       ack:  ack=1时,发送ack; ack=0时,发送nack* @retval      接收到的数据*/
uint8_t iic_read_byte(uint8_t ack)
{uint8_t i, receive = 0;IIC_SDA(1);for (i = 0; i < 8; i++ )    /* 接收1个字节数据,循环八次 */{IIC_SCL(1);if(IIC_READ_SDA == 1){receive |= (0x80 >> i);}  //SDA为1时,读取当前这位,为0时,不读取因为本身该位为0IIC_SCL(0);}if (!ack){iic_nack();     /* 发送nACK */}else{iic_ack();      /* 发送ACK */}return receive;
}//myiic.h#ifndef __MYIIC_H
#define __MYIIC_H#include "./SYSTEM/sys/sys.h"/******************************************************************************************/
/* 引脚 定义 */#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_8
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_9
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 *//******************************************************************************************//* IO操作 */
#define IIC_SCL(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SCL */#define IIC_SDA(x)        do{ x ? \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \}while(0)       /* SDA */#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA *//* IIC所有操作函数 */
void iic_init(void);            /* 初始化IIC的IO口 */
void iic_start(void);           /* 发送IIC开始信号 */
void iic_stop(void);            /* 发送IIC停止信号 */
void iic_ack(void);             /* IIC发送ACK信号 */
void iic_nack(void);            /* IIC不发送ACK信号 */
uint8_t iic_wait_ack(void);     /* IIC等待ACK信号 */
void iic_send_byte(uint8_t txd);/* IIC发送一个字节 */
uint8_t iic_read_byte(unsigned char ack);/* IIC读取一个字节 */#endif

iic软件驱动MPU6050代码

//MPU6050.c#include "./BSP/IIC/myiic.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/MPU6050/MPU6050.h"#define MPU6050_ADDRESS     0xD0void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)//向外设写数据
{iic_start();                //开始信号iic_send_byte(MPU6050_ADDRESS);//向该外设地址发送数据iic_wait_ack();                 //接收应答iic_send_byte(RegAddress);      //发送目标寄存器地址iic_wait_ack();iic_send_byte(Data);            //向该地址发送数据,这里是发送一个数据iic_wait_ack();/*for(int i = 0;i<8; i++)          //发送多个字节数据{iic_send_byte(Data);iic_wait_ack();}
*/iic_stop();                   //终止信号
}uint8_t MPU6050_ReadReg(uint8_t RegAddress)    //从外设读取数据
{uint*_t Data;iic_start();                //开始信号iic_send_byte(MPU6050_ADDRESS);//向该外设地址发送数据iic_wait_ack();                 //接收应答iic_send_byte(RegAddress);      //发送目标寄存器地址iic_wait_ack();iic_start();                //重新起始iic_send_byte(MPU6050_ADDRESS | 0x01)   //将最后一位变1,进行从机的读取数据iic_wait_ack();Data = iic_read_byte();         //读取数据iic_nack();                     //因为读取一个字节,所以不用产生应答iic_stop();
/*for(int i = 0;i < n;i++)        //读取n个字节,就要产生应答{Data = iic_read_byte();iic_ack();}
*/return Data;
}void MPU6050_Init(void)
{iic_init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);      //解除睡眠,X轴陀螺仪时钟MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x01);      //6个轴都不需要待机MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);      //选择十分频的采样率MPU6050_WriteReg(MPU6050_CONFIG,0x06);          //滤波参数给最大MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);     //陀螺仪最大量程MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);    //加速度计最大量程}void MPU6050_GetData(struct MPU6050_Data* p)    //获得芯片记录的各类数据
{uint16_t DataH,DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);  //获取加速度x轴数据DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);p->AccX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);p->AccY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);p->AccZ = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);   //获取陀螺仪x轴数据DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);p->GyroX = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);p->GyroY = (DataH << 8) | DataL;DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);p->GyroZ = (DataH << 8) | DataL;
}uint8_t MPU6050_GetID(void)                 //获取芯片ID号
{return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}//MPU6050.h#ifndef __MPU6050_H
#define __MPU6050_H#include "./SYSTEM/sys/sys.h"typedef struct MPU6050_Data{uint16_t AccX;      //加速度x轴数据uint16_t AccY;uint16_t AccZ;uint16_t GyroX;     //陀螺仪x轴数据uint16_t GyroY;uint16_t GyroZ;
}Data;void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
uint8_t MPU6050_GetID(void);
void MPU6050_GetData(struct MPU6050_Data* p);#define MPU6050_SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
#define MPU6050_CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
#define MPU6050_GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define MPU6050_ACCEL_CONFIG    0x1C    //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define MPU6050_ACCEL_XOUT_H    0x3B
#define MPU6050_ACCEL_XOUT_L    0x3C
#define MPU6050_ACCEL_YOUT_H    0x3D
#define MPU6050_ACCEL_YOUT_L    0x3E
#define MPU6050_ACCEL_ZOUT_H    0x3F
#define MPU6050_ACCEL_ZOUT_L    0x40
#define MPU6050_TEMP_OUT_H      0x41
#define MPU6050_TEMP_OUT_L      0x42
#define MPU6050_GYRO_XOUT_H     0x43
#define MPU6050_GYRO_XOUT_L     0x44
#define MPU6050_GYRO_YOUT_H     0x45
#define MPU6050_GYRO_YOUT_L     0x46
#define MPU6050_GYRO_ZOUT_H     0x47
#define MPU6050_GYRO_ZOUT_L     0x48
#define MPU6050_PWR_MGMT_1      0x6B    //电源管理,典型值:0x00(正常启用)
#define MPU6050_PWR_MGMT_2      0x6C    //电源管理寄存器2
#define MPU6050_WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)#endif

main.c

int main(void)
{Data Data1;int ID;OLED_Init();        //显示屏初始化MPU6050_Init();      //MPU6050初始化  OLED_ShowString(1,1,"ID:");ID = MPU6050_GetID();        //获取芯片IDwhile(1){MPU6050_GetData(&Data1);OLED_ShowSignedNum(2,1,Data1.AccX,5);    //获取x的加速度值}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/605223.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【蓝桥杯软件赛 零基础备赛20周】第7周——二叉树

文章目录 1 二叉树概念2 二叉树的存储和编码2.1 二叉树的存储方法2.2 二叉树存储的编码实现2.3 二叉树的极简存储方法 3 例题4 习题 前面介绍的数据结构数组、队列、栈&#xff0c;都是线性的&#xff0c;它们存储数据的方式是把相同类型的数据按顺序一个接一个串在一起。简单的…

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax类图 【大数据进阶第三阶段之Datax学习笔记】使用…

看直播怎么录屏?精选工具助你轻松录制!

随着网络直播平台的兴起&#xff0c;观看直播已经成为人们日常生活的一部分。然而&#xff0c;有时我们可能想要保存直播内容以便日后回顾或分享。可是看直播怎么录屏呢&#xff1f;在本文中&#xff0c;我们将介绍两种录制直播的方法&#xff0c;通过这些步骤&#xff0c;你可…

Verilog学习记录

目录 一、Verilog简介 &#xff08;一&#xff09;Verilog 的主要特性 &#xff08;二&#xff09;Verilog的主要应用 &#xff08;三&#xff09;Verilog设计方法 二、Verilog基础语法 &#xff08;一&#xff09;标识符和关键字 &#xff08;二&#xff09;Verilog数据…

内外网文件交换系统实用技巧揭秘:安全、效率、便捷一个不少

内外网文件交换系统是一种专门设计用于在企业内部网络&#xff08;内网&#xff09;与外部网络&#xff08;外网&#xff09;之间安全传输文件的技术解决方案。在企业环境中&#xff0c;出于安全考虑&#xff0c;内部网络通常与外部网络隔离&#xff0c;以防止未经授权的访问和…

shp文件与数据库(创建表)

前言 第三方库准备 shp文件是什么&#xff1f;笔者就不多做解释。后面将使用python的一些第三方库 1、sqlalchemy 2、pyshp 3、geoalchemy2 4、geopandas 这四个是主要的库&#xff0c;具体怎么使用可以参考相关教程&#xff0c;当然还有其他库&#xff0c;后面在介绍。…

信源编码与信道转移矩阵

目录 一. 信息论模型 二. 点对点通信模型 三. 信源编码 四. 信道转移矩阵 4.1 二进制对称信道 4.2 二进制擦除信道 五. 小结 &#xff08;1&#xff09;信道直射与反射 &#xff08;2&#xff09;信道散射 &#xff08;3&#xff09; 信道时变性 一. 信息论模型 194…

【AI视野·今日Robot 机器人论文速览 第七十一期】Fri, 5 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Fri, 5 Jan 2024 Totally 11 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Machine Learning in Robotic Ultrasound Imaging: Challenges and Perspectives Authors Yuan Bi, Zhongliang Jiang, Felix D…

redis可视化工具 RedisInsight

redis可视化工具 RedisInsight 1、RedisInsight是什么2、下载RedisInsight3、使用RedisInsight4、其他redsi可视化工具 1、RedisInsight是什么 RedisInsight 是一个用于管理和监控 Redis 数据库的图形用户界面&#xff08;GUI&#xff09;工具。它是由 Redis Labs 开发的&…

idea使用ssh连接docker,并通过Dockerfile文件,直接在idea中启动docker应用,并进行远程debug

idea使用ssh连接docker&#xff0c;并通过Dockerfile文件&#xff0c;直接在idea中启动docker应用&#xff0c;并进行远程debug 第一步: idea通过ssh连接docker第二步&#xff1a;使用Dockerfile文件在远程启动应用第三步: 远程debug 容器运行的好处是减轻本地运行的负担(本地电…

NSSCTF 2048

开启环境: 按F12查看网络,看到2048.js文件,打开 修改score>20000或者直接运行:(控制台输入) alert(String.fromCharCode(24685,21916,33,102,108,97,103,123,53,51,49,54,48,99,56,56,56,101,50,53,99,51,102,56,50,56,98,50,51,101,51,49,54,97,55,97,101,48,56,51,125)); …

Quartus II 13.1的安装及使用

Quartus II 13.1的安装及使用_quartus13.1-CSDN博客1.3 Verilog 环境搭建 | 菜鸟教程 学习 Verilog 做仿真时&#xff0c;可选择不同仿真环境。FPGA 开发环境有 Xilinx 公司的 ISE&#xff08;目前已停止更新&#xff09;&#xff0c;VIVADO&#xff1b;因特尔公司的 Quartu…

Marching Cubes算法再回顾

1,确定包含等值面的体元 首先介绍一下 体元的概念&#xff0c;体元是三维图像中由相邻的八个体素点组成的正方体方格&#xff0c;英语也叫 Cube&#xff0c;体元中角点函数值分为两种情况&#xff0c;一种是大于等于给定等值面的值 C0 ,则将角点设为 1 称该角点在等值面内部&a…

本地部署 gemini-openai-proxy,使用 Google Gemini 实现 Openai API

本地部署 gemini-openai-proxy&#xff0c;使用Google Gemini 实现 Openai API 0. 背景1. 申请 Google Gemini API key2. (Optional)Google Gemini 模型说明3. gemini-openai-proxy Github 地址4. 本地部署 gemini-openai-proxy5. 测试 0. 背景 使用 Google Gemini 实现 Opena…

Java 之 CAS(CompareAndSwap)底层原理详解

目录 一. 前言 二. CAS 底层原理 2.1. 代码实例 2.2. 源码分析 2.3. 底层汇编 2.4. ABA 问题 三. 总结 3.1. CAS 缺点 3.2. CAS 会导致 ABA 问题 一. 前言 CAS 的全称是 Compare-And-Swap&#xff0c;它是 CPU 并发原语。它的功能是判断内存某个位置的值是否为预期值。…

MySQL 8.0 开关 Redo Logging

一 前言 前几天有客户测试使用云数据库的时候提出 要禁止mydumper 关闭redo log的操作 (说白了就是导入数据时保持MySQL 实例的redo logging功能)&#xff0c; 这才想起 在 MySQL 8.0.21 版本中&#xff0c;开启了一个新特性 “Redo Logging 动态开关”。 在新实例导数据的场…

【IPC通信--消息队列】

消息队列&#xff08;也叫做报文队列&#xff09;是一个消息的链表。可以把消息看作一个记录&#xff0c;具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息&#xff1b;对消息队列有读权限的进程则可以从消息队列中读走消息…

[C#]Onnxruntime部署Chinese CLIP实现以文搜图以文找图功能

【官方框架地址】 https://github.com/OFA-Sys/Chinese-CLIP 【算法介绍】 在当今的大数据时代&#xff0c;文本信息处理已经成为了计算机科学领域的核心议题之一。为了高效地处理海量的文本数据&#xff0c;自然语言处理&#xff08;NLP&#xff09;技术应运而生。而在诸多N…

电子实验室设备:从零开始配置实验室(一)

本文译自 Electronics Lab Equipment: Kitting out a Lab from Scratch 随着多次国际迁徙以及在几家公司&#xff08;或其分支机构&#xff09;工作&#xff0c;尤其是在没有强大电子工程团队的情况下&#xff0c;我不得不为自己和客户设置多个电子实验室。那些计划进行内部测试…