| **银杏科技有限公司旗下技术文档发布平台** |||| |技术支持电话|**0379-69926675-801**||| |技术支持邮件|Gingko@vip.163.com||| ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | V1.0 | 2019-02-16 | gingko | 初次建立 | ===== STM32CubeMX教程七——I2C实验 ===== 1. 在主界面选择File-->New Project 或者直接点击ACCEE TO MCU SELECTOR {{ :icore4t:icore4t_cube_7_1.png?direct |}} 2. 出现芯片型号选择,搜索自己芯片的型号,双击型号,或者点击Start Project进入配置 在搜索栏的下面,提供的各 种查找方式,可以选择芯片内核,型号,等等,可以帮助你查找芯片。本实验选取的芯片型号为:STM32H750IBKx。 {{ :icore4t:icore4t_cube_7_2.png?direct |}} 3. 配置RCC,使用外部时钟源 {{ :icore4t:icore4t_cube_7_3.png?direct |}} 4. 时基源选择SysTick {{ :icore4t:icore4t_cube_7_4.png?direct |}} 5. 将PA10,PB7,PB8设置为GPIO_Output {{ :icore4t:icore4t_cube_7_5.png?direct |}} 6. 引脚模式配置 {{ :icore4t:icore4t_cube_7_6.png?direct |}} {{ :icore4t:icore4t_cube_7_7.png?direct |}} 7. 时钟源设置,选择外部高速时钟源,配置为最大主频 {{ :icore4t:icore4t_cube_7_8.png?direct |}} 8. 工程文件的设置, 这里就是工程的各种配置 我们只用到有限几个,其他的默认即可 IDE我们使用的是 MDK V5.27 {{ :icore4t:icore4t_cube_7_9.png?direct |}} 9. 点击Code Generator,进行进一步配置 {{ :icore4t:icore4t_cube_7_10.png?direct |}} * **Copy all used libraries into the project folder** * **将HAL库的所有.C和.H都复制到所建工程中** * **优点**:这样如果后续需要新增其他外设又可能不再用STM32CubeMX的时候便会很方便 * **缺点**:体积大,编译时间很长** * Copy only the necessary library files** * **只复制所需要的.C和.H(推荐)** * **优点**:体积相对小,编译时间短,并且工程可复制拷贝 * **缺点**:新增外设时需要重新用STM32CubeMX导入 * **Add necessary library files as reference in the toolchain project configuration file** * **不复制文件,直接从软件包存放位置导入.C和.H** * **优点**:体积小,比较节约硬盘空间 * **缺点**:复制到其他电脑上或者软件包位置改变,就需要修改相对应的路径 * 自行选择方式即可 10. 然后点击GENERATE CODE 创建工程 {{ :icore4t:icore4t_cube_7_11.png?direct |}} 创建成功,打开工程。 \\ \\ \\ ===== 实验七:I2C通信实验——驱动电源管理AXP152 ===== ==== 一、 实验目的与意义 ==== - 了解STM32 I2C结构 - 了解STM32 I2C特征 - 掌握I2C的使用方法 - 掌握STM32 HAL库中I2C属性的配置方法 - 掌握KEILMDK 集成开发环境使用方法 ==== 二、 实验设备及平台 ==== - iCore4T 双核心板。[[https://item.taobao.com/item.htm?spm=a1z10.1-c.w137644-251734891.3.5923532fDrMDOe&id=610595120319|点击购买]] - JLINK(或相同功能)仿真器。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]] - Micro USB线缆。 - Keil MDK 开发平台。 - STM32CubeMX开发平台。 - 装有WIN XP(及更高版本)系统的计算机。 ==== 三、 实验原理 ==== === 1、 I2C简介 === * I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。是微电子通信控制领域广泛采用的一种总线标准。 === 2、 I2C工作方式 === I2C设备之间常用的连接方式如下图。 {{ :icore4t:icore4t_arm_hal_7_1.png?direct |}} * 可以看到上图中有两根总线,一根是主控时序 SCL, 另一根是主控数据SDA。“总线”指多个设备公用的信号线, 在一个 I2C 通信总线中,可连接多个 I2C设备通信,支持多个通信主机及多个通信从机。 * 为了区分设备,每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。 当有多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定由哪个设备占用总线。 * I2C 支持不同的通信速度,标准速度高达100kHz, 快速速度高达 400kHz。 === 3、 I2C通信流程 === * 通信开始:主设备发送起始条件(启动数据传输并生成时钟信号);主设备发送要寻址的从设备的地址以及通信方向。 * 通信过程中:主设备发送数据,从设备发送应答;从设备发送数据,主设备发送应答。 * 通信结束:主设备发送停止条件。 {{ :icore4t:icore4t_arm_hal_7_2.png?direct |}} * 空闲状态:SDA和SCL两条信号线同时处于高电平。 * 起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号, 而不是一个电平信号。 * 停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。 {{ :icore4t:icore4t_arm_hal_7_3.png?direct |}} * **应答信号ACK:** * 发送器每发送一个字节, 就在时钟脉冲9期间释放数据线, 由接收器反馈一个应答信号。 * 应答信号为低电平时, 为有效应答位(ACK) , 表示接收成功。 * 应答信号为高电平时, 为非应答位(NACK) , 表示接收没有成功。 * 对于反馈有效应答位ACK的要求是, 接收器在第9个时钟脉冲之前的。 * 低电平期间将SDA线拉低, 并且确保在该时钟的高电平期间为稳定的低电平。 {{ :icore4t:icore4t_arm_hal_7_4.png?direct |}} * **数据有效性:** * I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 {{ :icore4t:icore4t_arm_hal_7_5.png?direct |}} * 我们I2C通过SDA和SCL即可实现通信,那么我们在STM32上直接通过控制两个 GPIO口的电平,即可利用这个来产生通信的时序,这种方法称为“软件I2C”。还有一种是“硬件 I2C”,是STM32的I2C片上外设专门负责实现 I2C 通信协议,配置好该外设,它就会自动地根据协议要求产生通信信号,收发数据并缓存,CPU只要检测该外设的状态和访问相应寄存器,即可实现数据的接发。 === 4、 AXP152简介 === * AXP152是一款高度集成的电源管理芯片,包含 4 路高效 DCDC、7 路 LDO,输出电压可灵活配置。AXP152用于需要多路电源转换的应用场景,并可与本公司其它 PMU 配合构成完整的单芯或多芯锂电池(锂离子或锂聚合物)应用场景电源解决方案,充分满足目前日益复杂的应用处理器系统对于电源多输出、大电流、高精度的要求。 * AXP152 内部集成了过压欠压保护(OVP/UVP)、过温保护(OTP)等保护功能,可充分保障供电的安全稳定。 * AXP152 提供了一个两线串行通信接口:Two Wire Serial Interface (TWSI),应用处理器可以通过这个接口设置各路输出的电压,打开/关闭某些电源输出,以及配置中断和睡眠唤醒系统。 * 原理图如下所示: {{ :icore4t:icore4t_arm_hal_7_6.png?direct |}} ==== 四、 实验程序 ==== === 1. 主函数 === int main(void) { HAL_Init(); SystemClock_Config(); i2c.initialize(); axp152.initialize(); axp152.set_dcdc1(3500);//[ARM & FPGA BK1/2/6 &OTHER] axp152.set_dcdc2(1200);//[FPGA INT & PLL D] axp152.set_aldo1(2500);//[FPGA PLL A] axp152.set_dcdc4(3300);//[POWER_OUTPUT] axp152.set_dcdc3(3300);//[FPGA BK4][Adjustable] axp152.set_aldo2(3300);//[FPGA BK3][Adjustable] axp152.set_dldo1(3300);//[FPGA BK7][Adjustable] axp152.set_dldo2(3300);//[FPGA BK5][Adjustable] MX_GPIO_Init(); while (1) { } } === 2. I2C配置函数 === static int initialize(void) { __HAL_RCC_GPIOB_CLK_ENABLE(); SDA_OUTPUT; SCL_OUTPUT; SDA_ON; SCL_ON; return 0; } //起始信号 static int start(void) { SDA_ON; delay(); SCL_ON; delay(); SDA_OFF; delay(); SCL_OFF; delay(); SDA_OFF; delay(); SCL_OFF; delay(); return 0; } //终止信号 static int stop(void) { // SDA_OUTPUT; SDA_OFF; delay(); SCL_ON; delay(); SDA_ON; delay(); return 0; } //应答 static int ack(char a) { // SDA_OUTPUT; if (a) { SDA_OFF; }else { SDA_ON; } delay(); SCL_ON; delay(); SCL_OFF; delay(); return 0; }; //发送 static int write(unsigned char data) { unsigned char i = 8; // SDA_OUTPUT; for (i = 0; i < 8; i++) { /*要传送的数据长度为8 位*/ if ((data << i) & 0x80) SDA_ON; /*判断发送位*/ else SDA_OFF; delay(); SCL_ON; delay(); SCL_OFF; } SDA_INPUT; delay(); delay(); SCL_ON; delay(); if (SDA_DATA) i2c.ack_flag = 0; else i2c.ack_flag = 1; /*判断是否接收到应答信号*/ SCL_OFF; SDA_OUTPUT; delay(); return 0; } //接收 static unsigned char read(void) { unsigned char retc; unsigned char BitCnt; retc = 0; SDA_ON; /*置数据线为输入方式*/ SDA_INPUT; for (BitCnt = 0; BitCnt < 8; BitCnt++) { delay(); SCL_OFF; /*置时钟线为低,准备接收数据位*/ delay(); SCL_ON; /*置时钟线为高使数据线上数据有效*/ delay(); retc = retc << 1; if ((SDA_DATA) == 1) retc = retc + 1; /*读数据位,接收的数据位放入retc 中 */ delay(); } SCL_OFF; delay(); SDA_OUTPUT; return(retc); } //接受数据 static int read_nbyte(unsigned char sla, unsigned char suba, unsigned char *s, unsigned char no) { unsigned char i; i2c.start(); /*启动总线*/ i2c.write(sla); /*发送器件地址*/ // if(i2c.ack_flag==0)return(0); i2c.write(suba); /*发送器件子地址*/ // if(i2c.ack_flag==0)return(0); i2c.start(); i2c.write(sla + 1); // if(i2c.ack_flag==0)return(0); for (i = 0; i < no - 1; i++) { *s = i2c.read(); /*发送数据*/ i2c.ack(1); /*发送就答位*/ s++; } *s = i2c.read(); i2c.ack(0); i2c.stop(); return(1); } //发送数据 static int write_nbyte(unsigned char sla, unsigned char suba, unsigned char *s, unsigned char no) { unsigned char i; i2c.start(); i2c.write(sla); if (i2c.ack_flag == 0) return(0); i2c.write(suba); if (i2c.ack_flag == 0) return(0); for (i = 0; i < no; i++) { i2c.write(*s); if (i2c.ack_flag == 0) return(0); s++; } i2c.stop(); return(1); } === 3. AXP初始化函数 === int initialize(void) { unsigned char ver; int rc; rc = i2c.read_nbyte(AXP152_I2C_ADDR,AXP152_CHIP_VERSION,&ver,1); if (rc){ return rc; } if (ver != 0x05){ return -1; } return 0; } === 4. 电压参数调整函数 === static unsigned char axp152_mvolt_to_target(int mvolt, int min, int max, int div) { if (mvolt < min) mvolt = min; else if (mvolt > max) mvolt = max; return (mvolt - min) / div; } int set_dcdc2(unsigned int mvolt) { unsigned char target = axp152_mvolt_to_target(mvolt, 700, 2275, 25); return i2c.write_nbyte(AXP152_I2C_ADDR,AXP152_DCDC2_VOLTAGE,&target,1); ==== 五、 实验步骤 ==== - 把仿真器与iCore4T的SWD调试口相连(直接相连或者通过转接器相连); - 把iCore4T通过Micro USB线与计算机相连,为iCore4T供电; - 打开Keil MDK 开发环境,并打开本实验工程; - 烧写程序到iCore4T上; - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。 ==== 六、 实验现象 ==== 用万用表测量各测试点电压与程序设定电压一致。