第六节:STM32基于HAL库的IIC通信

IIC通信


《用CubeMX学习STM32》

注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏


6、STM32 I2C通信

前言: IIC协议简介

  维基百科的解释如下: I2C(Inter-Integrated Circuit)字面上的意思是积体电路之间,它其实是I2C Bus简称,所以中文应该叫集成电路总线,它是一种串行通讯汇流排,使用多主从架构,由飞利浦公司在1980年代为了让主机板、嵌入式系统或手机用以连接低速周边装置而发展。I2C的正确读法为“I平方C”("I-squared-C"),而“I二C”("I-two-C")则是另一种错误但被广泛使用的读法。自2006年10月1日起,使用I2C协定已经不需要支付专利费,但制造商仍然需要付费以取得I2C从属装置位址。

   我们需要了解的是 : I2C通信只需要两根线即可进行数据传输; 即串行数据线(SDA::Serial DAta)和串行时钟线(SCL::Serial CLock); IIC总线具有多主设备的优点, 就是有多个主机进行数据发送并且不会有混乱.

  IIC总线可以用简单、优雅四个字形容,很方便。下面是IIC的时序图:

在这里插入图片描述

IIC总共有三种信号:开始信号,结束信号,应答信号

说明:高电平为1,低电平为0

1、图中S即为起始信号: SCL处于1时, SDA由高变低↓—>Start

下面是STM32的这部分代码,每句话我基本上都加了注释,可以对照时序图看, 便于理解
在这里插入图片描述

2、图中末尾P为结束信号: SCL=1, SDA 由低变高↑

在这里插入图片描述

3、数据传送: 每次数据传送都是8个字节; SCL=1时, SDA的数据不可以变化, 只有SCL为低电平, 数据线的数据才可以变化;

3.1、 数据传输流程:SCL=0, —>开始数据传输, 传输完一位之后,—> SCL=1(拉高时钟线);===
下面接着循环, 直到传输完一个字节8位数据.

下面举个例子:

e.g.

传输1001 1100?

SCL=0 --> SDA=1 --> SCL=1 (先传送最高位MSB)

SCL=0 --> SDA=0 --> SCL=1

SCL=0 --> SDA=0 --> SCL=1

**Tips:**在IIC协议中,起始信号必须有. 因为IC必须知道什么时候开始了,才可以正确判断接受数据.

下面开始Cube配置+IAR编程


6.1 操作简介

  (1) 我所使用的STM32开发板板载了一个24C02的EEPROM存储芯片; 这个芯片就是通过IIC总线和单片机通信的;

  (2) 通过GPIO软件模拟IIC通信 , 实现对24C02芯片内部数据的读写操作 .

注:

  本次实验的代码是用的原子的底层代码, 修改了部分代码, 和Cube配置的工程以及HAL库函数匹配. 野火的例程没有看过,如果这个代码又有什么限制或者问题, 可以评论或者私信告诉我, 共同学习,感激不尽.

6.1 软件流程图

开机检测24C02--->主循环检测按键--->串口打印相关信息...

在这里插入图片描述


6.2 硬件接口

以我用的单片机为例:

在这里插入图片描述

   但是这里并没有用板子上的硬件 IIC, 只是用这两个对应的引脚做软件模拟 IIC


Step1 : STM32CubeMX配置

  • (1) 像前面那样配置好基础的东西[RCC--SYS--时钟树配置不变]
    • 还要配置 串口按键 ; 时钟树的配置跟之前的博客都一样
    • Tips: Click the blue word to open the corresponding blog link

  • (2) 配置IIC通信用的两个引脚(SCL&SDA)
    • 两个引脚都配置为输出模式, 在程序中需要改变引脚方向, 那个时候直接操作寄存器改动引脚输入输出即可, 配置的时候先默认配置一个输出;

    • 在这里插入图片描述

    • 在这里插入图片描述

补充: 后面又加上了两个LED引脚, 用以做指示

  • 在这里插入图片描述

  • (3) Project Manager and Generate Code
    • 在这里插入图片描述
    • 在这里插入图片描述


Step2 : IAR或Keil编程

  • (1) IIC部分代码

  • 我把我改过部分的底层代码分享在网盘里面
    链接:https://pan.baidu.com/s/17ogW2r-WzN9u-w511VzBJQ
    提取码:9m4v

    • .c文件放在 src 文件夹,.h文件复制到 Inc 文件夹

    • 在这里插入图片描述

    • 在myiic.h里面有两句宏定义SDA_OUT()和SDA_IN(); 如果你用的是F4的板子是可以直接用的, 但是如果用的是F1的或者其他的, 这个宏定义要改一下, 因为不同的芯片寄存器的名字和操作不太一样. 如果有人用的F1在这里遇到困难可以评论或者私信我, 这里就不单独写了

说明 :24cxx文件是24CXX系列芯片的底层驱动文件, myiic文件是修改后的iic通信的驱动文件; 在主函数里面就是调用myiic里面的函数去实现通信的功能

部分底层代码分析

  大概说一下底层驱动, 24cxx文件是通过iic协议对24c02芯片通信的底层驱动,直接用就可以了。
  myiic文件是iic的关键.
  关于起始信号, 结束信号就不多说了
  在myiic.h中宏定义了SDA引脚的输入输出模式, 因为读数据的时候需要SDA这根线为输入模式, 往里面读数据
  关于应答信号之类的几个函数,有兴趣可以去了解一下具体的IIC的协议总结或者数据手册

发送字节函数
  在这里插入图片描述

 IIC协议发送字节, 一个字节8位, 通过一个for循环发送;

txd是要发送的一个字节, IIC是先传输最高位, 所以让txd和0x80相与, 再右移7位

数据为1就给数据线(SDA)引脚写高电平, 然后txd左移一位,进入下一循环, 逐渐把8bits的数据发送完毕

读一个字节函数
在这里插入图片描述

 IIC发送数据是往外发送数据, 所以SDA为输出模式, 但是读取字节是把外面的读进来;
 举个形象一点的例子, 你的大脑就是24C02储存芯片, 你的身体器官就是IIC,即你的身体器官是通过IIC协议与外界进行数据交换的
 发送字节就是你用嘴巴给别人说话把你脑子里想的东西告诉别人;   而接收字节就是你通过眼睛读书, 把知识记到脑子里

 这样就很好理解了吧

在这里插入图片描述

  • (2) 按键部分
    • 新建一个文件Ctrl+N—>Ctrl+S保存为 key.c到Src文件夹 ; 再新建一个保存在Inc文件夹, 命名为key.h
    • 把.c和.h文件添加到工程中
      +在这里插入图片描述
      • 写代码
      • 在这里插入图片描述

#include "key.h"
#include "main.h" 

/******************************************************************************************************
 *【文件名称】   : key.c
 *【文件描述】   : 核心板板载按键驱动代码
 *【文件功能】   : 实现按键输入扫描功能
 *【主控芯片】   : STM432F407zg
 *【实验平台】   : STM32F4xx开发板
 *【编写环境】   : IAR 8.30.1
 *【编写时间】   : 2019-12-31
 *【作    者】   : 李剀(KevinLee)
 *【历史记录】   :   
					<1>	$【修改时间】
							$【修改内容】
							$【修改详情】
							$【修改人员】

*******************************************************************************************************/


/**
  * @brief  按键处理函数
  * @param  mode:0,不支持连续按;1,支持连续按;
  * @retval 0: 没有任何按键按下     1: KEY0按下
  *                                 2: WKUP按下 WK_UP
  */
uint8_t KEY_Scan(uint8_t mode)
{	 
		static uint8_t key_up = 1;//按键按松开标志
		if (mode)
				key_up=1;  //支持连按		  
		if (key_up && (KEY0 == 0 || WK_UP != 0))
		{
				HAL_Delay(10);//去抖动 
				key_up = 0;
				if(KEY0 == 0)
						return 1;
				else if(WK_UP != 0)
						return 2;
		}else if(KEY0 != 0 && WK_UP == 0)
				key_up = 1;
		
		return 0;// 无按键按下
}

key.h代码如下
在这里插入图片描述

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h" 
/******************************************************************************************************
 *【文件名称】   : key.h
 *【文件描述】   : 核心板板载按键驱动代码
 *【文件功能】   : 实现按键输入扫描功能
 *【主控芯片】   : STM432F407zg
 *【实验平台】   : STM32F4xx开发板
 *【编写环境】   : IAR 8.30.1
 *【编写时间】   : 2019-12-31
 *【作    者】   : 李剀(KevinLee)
 *【历史记录】   :   
					<1>	$【修改时间】
							$【修改内容】
							$【修改详情】
							$【修改人员】

*******************************************************************************************************/

#define KEY0 	HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)  //PE4
#define WK_UP 	HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin)  //PA0

#define KEY0_PRES		1   // 宏定义按键按下的键值
#define WKUP_PRES		2

uint8_t KEY_Scan(uint8_t);  		//按键扫描函数	

#endif

  • (3) 串口重定向printf

  • (4) main.c文件

    包含头函数

    • 在这里插入图片描述

    自定义变量

    • 在这里插入图片描述
    • TEXT_Buffer数组存放的是等会要写入24c02芯片的数据

    主函数变量定义

    • 在这里插入图片描述
    • key用于获取扫描按键值; datatemp数组作为传输数据的暂存地点

    初始化操作

    • 在这里插入图片描述
    • 在/ USER CODE BEGIN 2 /下, 先初始化IIC, 在测试串口, 并用串口打印提示信息, 然后检测存储芯片是否存在

  /* USER CODE BEGIN 2 */
  AT24CXX_Init();	//IIC初始化
  printf("Usart is Ok!!!\n");
  printf("***************************\n");
  printf("**    STM32 IIC TEST     **\n");
  printf("**      Kevin_8_Lee      **\n");
  printf("** KEY0:Write  WKUP:Read **\n"); // 打印提示信息; KEY0按下写数据;WKUP按下读数据
  printf("***************************\n");
  
  // 检测24C02芯片是否存在
  while(AT24CXX_Check())
  {
    printf("未检测到24C02!\n");
    HAL_Delay(500);
    HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // LED0闪烁
  }
  
  printf("24C02 Ready!\n");
  /* USER CODE END 2 */

while(1)循环

  • 在这里插入图片描述
  • 循环进行安检扫描, 如果KEY0按下, 就把之前定义的一个字符串数组的数据写入24C02, 如果检测到WKUP按键按下就把24C02内部的数据读取出来并打印在串口
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    key = KEY_Scan(0);	// 按键扫描获取键值
    
    // 如果KEY0按下,则向24C02芯片写入指定数据
    if (key == KEY0_PRES)
    {
      printf("开始写入24C02...\n");
      AT24CXX_Write(0,(uint8_t *)TEXT_Buffer,SIZE);
      printf("传输完成\n\n");
    }
    // 如果WKUP按键按下,则从24C02芯片读出数据, 并打印在串口
    if (key == WKUP_PRES)
    {
      printf("开始读24C02......\n");
      AT24CXX_Read(0,datatemp,SIZE);
      printf("读取到的数据为 : %s", datatemp);
      
    }
    
    // 下面的是进行一定的延时, 保证上面扫描安全运行, 同事
	// 以LED闪烁提示系统正在运行
    i++;
    HAL_Delay(10);
    if (i == 20)
    {
      HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
      i = 0;
    }
  }
  /* USER CODE END 3 */

实际效果

串口助手打印出的结果:
在这里插入图片描述


2020年4月19日2020年4月19日18:00:01补充:完整工程链接—>IIC通信


Don’t ever let somebody tell you, you can’t do something!!!


Author : 李光辉
date : Sun Apr 19 16:28:12 CST 2020
blog ID: Kevin_8_Lee
blog site : https://blog.csdn.net/Kevin_8_Lee

发布了22 篇原创文章 · 获赞 65 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Kevin_8_Lee/article/details/105617640