经销商自己做网站合适吗,产品包装设计与制作,南宁网站托管,融资渠道#x1f680;write in front#x1f680; #x1f50e;大家好#xff0c;我是黄桃罐头#xff0c;希望你看完之后#xff0c;能对你有所帮助#xff0c;不足请指正#xff01;共同学习交流 #x1f381;欢迎各位→点赞#x1f44d; 收藏⭐️ 留言#x1f4dd;… write in front 大家好我是黄桃罐头希望你看完之后能对你有所帮助不足请指正共同学习交流 欢迎各位→点赞 收藏⭐️ 留言 本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理 Projeet source code 工程代码放在了本人的Gitee仓库iPickCan (iPickCan) - Gitee.com 引用
STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
Keil5 MDK版 下载与安装教程STM32单片机编程软件_mdk528-CSDN博客
STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客
0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客
【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客
江科大STM32学习笔记上_stm32博客-CSDN博客
STM32学习笔记一基于标准库学习_电平输出推免-CSDN博客
STM32 MCU学习资源-CSDN博客
stm32学习笔记-作者: Vera工程师养成记
stem32江科大自学笔记-CSDN博客 术语
英文缩写描述GPIOGeneral Purpose Input Onuput通用输入输出AFIOAlternate Function Input Output复用输入输出AOAnalog Output模拟输出DODigital Output数字输出内部时钟源 CK_INTClock Internal内部时钟源外部时钟源 ETRExternal Trigger 时钟源 External 触发外部时钟源 ETRExternal Trigger mode 1外部时钟源 External 触发 时钟模式1外部时钟源 ETRExternal Trigger mode 2外部时钟源 External 触发 时钟模式2外部时钟源 ITRxInternal Trigger inputs外部时钟源ITRx Internal trigger inputs内部触发输入外部时钟源 TIxexTernal Input pin 外部时钟源 TIx external input pin外部输入引脚CCRCapture/Comapre Register捕获/比较寄存器OCOutput Compare输出比较ICInput Capture输入捕获TI1FP1TI1 Filter Polarity 1Extern Input 1 Filter Polarity 1外部输入1滤波极性1TI1FP2TI1 Filter Polarity 2Extern Input 1 Filter Polarity 2外部输入1滤波极性2DMADirect Memory Access直接存储器存取 正文
0. 概述
从 2024/06/12 定下计划开始学习下江协科技STM32课程接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发本文是视频教程 P2 STM32简介一讲的笔记。
1.MP6050
本节我们来用软件I2C读写MPU6050
接线图 由于我们这个代码使用的是软件I2C就是用普通的GPIO口手动翻转电平实现的协议。它并不需要STM32内部的外设资源支持。所以这里的端口其实可以任意指定不局限于这两个端口接在任意的两个普通的GPIO口就可以。
然后我们只需要在程序中配置并操作SCL和SDA对应的端口就行了。这算是软件I2C相比硬件I2C的一大优势就是端口不受限可以任意指定。
根据I2C协议的硬件规定SCL和SDA都应该外挂一个上拉电阻但是我们的接线这里并没有外挂上拉电阻。是因为上一节我们分析模块电路的时候提到过这个模块内部自带了上拉电阻所以外部的上拉电阻就不需要接了。
目前这里STM32是主机MPU6050是从机是一主一从的模型当然主机和从机的执行逻辑是完全不同的我们程序中一般只关注主机端的程序。
这里由于模块内置了下拉电阻所以引脚悬空的话就相当于接地。 MyI2C.c
由于我们本代码要使用软件I2C所以I2C的库函数我们就不用看了。软件I2C只需要用GPIO的读写函数就行了。
初始化函数
然后初始化函数中我们要做两个任务。第一个任务把SCL和SDA都初始化为开漏输出模式开漏输出低电平浮空输入也就是高阻态。第二个任务把SCL和SDA置高电平。 ⚠️⚠️⚠️注意开漏输出并不只能输出开漏输出模式仍然可以输入。 ⚠️⚠️⚠️输入时先输出1再直接读取输入数据寄存器就行了。 然后接下来我们就来完成I2C的六个时序基本单元。
起始条件
第一个基本单元是起始条件这里对应写一个函数。 起始条件SCL高电平期间SDA从高电平切换到低电平 我们首先把SCL和SDA都确保释放然后先拉低SDA再拉低SCL这样就能产生起始条件了。 在这里我们可以不断的调用SetBits和RetsetBits手动翻转高低电平。但是这样做的话会在后面的程序中出现非常多的地方来指定这个GPIO端口号。一方面这样做语义并不是很明显另一方面如果我们之后需要换一个端口就需要改动非常多的地方。所以这时我们就需要在上面做个定义把这个端口号统一替换一个名字这样无论是语义还是端口的修改都会非常方便。给端口号换一个名字有很多方法都能实现功能。在51单片机中我们一般使用sbit来定义端口的名称但是sbit并不是标准C语言的语法STM32也不支持这样做。这里一种简单的替换方法就是宏定义define。 修改引脚的时候直接在上面修改一下宏定义这是一种简单可行的方法在STM32程序中也是挺常见的一个操作。 进一步的如果觉得每次都需要定义port和pin比较麻烦还可以把这整个函数用宏定义进行替换并且用宏定义替换的函数还可以有参数叫有参宏。
以我们之前讲过的OLED的程序为例 在宏定义后面加一个括号里面写入形参在实际引用的时候传入实参。
这样实际上OLED_W_SCL(1)就等价于GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(1));
补充BitAction是什么意思
在STM32中用于强制将特定的操作数转换为一个位值将一个非零值转换为逻辑高电平(1)将零值转换为逻辑低电平(0)。
在GPI0操作中可以使用BitAction宏定义来设置引脚的状态例如通过调用GPI0 writeBit()函数来设置引脚的输出状态。
GPI0x表示GPIO端口GPI0 Pin表示具体的引脚位而BitAction表示要设置的引脚状态。 但是这种方法在移植到其他库或者其他种类单片机时很多人都不知道怎么修改。另外还有这种宏定义的方法如果换到一个主频很高的单片机中需要对软件的时序进行延时操作的时候也不太方便进一步修改。
所以综合以上缺点在这里我们就直接一点干脆再套个函数。如果单片机主频比较快也非常方便加一些延时比如每次操作引脚之后都要延时10us。 后面再调用这个W_SCL参数给1或0就可以释放或拉低SCL了。
对于STM32F1系列这里即使不加任何延时这个引脚翻转速度MPU6050也能跟得上。但是保险起见还是延时个十微秒。
如果要把这个程序移植到别的单片机就可以把这个函数里的操作替换为其他单片机对应的操作。比如SCL是51单片机的P10口就可以把GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);这句替换为P10BitValue。 操作SDA的函数
接下来封装一下操作SDA的函数 读和写不是同一个寄存器再定义一个函数 有了这三个函数的分装我们就实现了函数名称、端口号的替换。同时也可以很方便的修改时序的延时。当我们需要替换端口或者把这个程序移植到别的单片机中时就只需要对这前四个函数里的操作对应更改。
我们回到这个函数开始调用以上四个函数。
我们需要先把SCL和SDA都释放也就是都输出1然后先拉低SDA。再拉低SCL这就是起始条件的执行逻辑。 注意我们最好把释放SDA的放在前面。 如果起始条件之前SCL和SDA已经是高电平了先释放哪一个是一样的效果。 但是后面start还要兼容这里的重复起始条件sr。 如果sr最开始SCL是低电平SDA电平不敢确定所以保险起见趁SCL是低电平时先确保释放SDA再释放SCL这时SDA和SCL都是高电平。然后再拉低SDA拉低SCL这样start就可以兼容起始条件和重复起始条件了。 接下来继续终止条件 终止条件
终止条件SCL高电平期间SDA从低电平切换到高电平 果stop开始时SCL和SDA都已经是低电平了就先释放SCL再释放SDA就行了。但是在这个时序单元开始时SDA并不一定是低电平。 所以为了确保之后释放SDA能产生上升沿我们要在时序单元开始时先拉低SDA然后再释放SCL释放SDA。 然后是发送一个字节 发送一个字节
发送一个字节SCL低电平期间主机将数据位依次放到SDA线上高位先行然后释放SCL从机将在SCL高电平期间读取数据位所以SCL高电平期间SDA不允许有数据变化依次循环上述过程8次即可发送一个字节 实际上除了终止条件SCL以高电平结束所有的单元我们都会保证SCL以低电平结束这样方便各个单元的拼接。 SCL低电平变换数据高电平保持数据稳定由于是高位先行所以变换数据的时候按照先放最高位再放次高位依次把一个字节的每一位放在SDA线上每放完一位后执行释放SCL拉低SCL的操作驱动时钟运转。
Byte 0x80 就是保留字节的高位对其他位清0假设Byte是xxxx xxxxx 由于调用的这个函数中的参数最后会被强制转换成bitAction类型所以非0即1所以最终MyI2C_W_SDA(Byte (0x80 i))也相当于传了一个1 接着继续写接收一个字节
接收一个字节
接收一个字节SCL低电平期间从机将数据位依次放到SDA线上高位先行然后释放SCL主机将在SCL高电平期间读取数据位所以SCL高电平期间SDA不允许有数据变化依次循环上述过程8次即可接收一个字节主机在接收之前需要释放SDA 主机需要先释放SDA释放SDA也相当于切换为输入模式。
SCL低电平变换数据高电平读取数据实际上就是一种读写分离的设计低电平时间定义为写的时间高电平时间定义为读的时间。
SCL高电平时SDA下降沿为起始条件SDA上升沿为终止条件。这个设计也保证了起始和终止的特异性能够让我们在连续不断的波形中快速的定位起始和终止。因为起始终止和数据传输的波形有本质区别。数据传输时SCL高电平不许动SDA起始终止条件下是SCL高电平必须动SDA 注意I2C是在进行通信通信是有从机的当主机不断驱动SCL时钟时从机就有义务去改变SDA的电平。所以主机每次循环读取SDA的时候这个读取到的数据是从机控制的这个数据也正是从机想要给我们发送的数据。 发送应答
然后发送应答和接收应答只要复制发送一个字节和接收一个字节的函数修改一下就可以了。 发送应答主机在接收完一个字节之后在下一个时钟发送一位数据数据0表示应答数据1表示非应答 接收应答 接收应答主机在发送完一个字节之后在下一个时钟接收一位数据判断从机是否应答数据0表示应答数据1表示非应答主机在接收之前需要释放SDA 注意I2C的引脚都是开漏输出弱上拉的配置。主机输出1并不是强制SDA为高电平而是释放SDAI2C通信时主机释放了SDA从机在此时把SDA再拉低的。所以这里即使之前主机把SDA置1再读取SDA读到的值也可能是0读到0代表从机给了应答读到1代表从机没给应答。 测试应答功能
想要测试应答功能时主函数可以这样调用 这样就可以测试从机给不给应答的时序
1101 000是从机的地址可以理解为是从机的名字最低位的0是表示“写入操作” 这样运行后显示从机可以给我们应答 我们接下来讲一下通过AD0引脚改名的功能。
通过AD0引脚改名的功能
我们可以把一根飞线连接AD0引脚和VCC 这时MPU6050的从机地址就是1101 001了。 这个时候运行就发现从机没有给我们应答了因为它刚刚改名成1101 001了。 这个时候把飞线拔掉再次运行发现它又可以应答了。 这就是改名的实验现象。目前我们这个芯片只有AD0一个引脚它就只能拥有两个名字。如果有AD0和AD1两个引脚就可以拥有总共四个名字。如果有更多的可配置引脚就有更多的改名机会。当我们需要一条总件挂载多个相同型号的设备时就可以利用这个改名的功能避免名字也就是从机地址的重复。