pal库 IIC

2023-12-22 04:52
文章标签 iic pal

本文主要是介绍pal库 IIC,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数据接收的流程

在这里插入图片描述
下面的流程可以用一个接口来实现 一个函数接口
第一个就是从机的地址 第二个参数就是接收数据的缓冲区 第三个参数就是 接收数据的大小
RXNE和BTF标志位
在这里插入图片描述
当两个寄存器(TDR)和移位寄存器都满的时候标志位BTF就为1 表示缓冲区已满
ACK和ANK的发送
在之前都是主机发送数据 从机回复ACK或者NAK信号表示信号接收完毕 到数据的接收就反过来了 就是主机回复ACK或者NAK信号
在这里插入图片描述
CR寄存器的一个标志位 来控制发送的是ACK还是NAK信号
停止位的发送
在这里插入图片描述
向状态寄存器的STOP位写1 如果有数据正在接收那么就会在接受完这个数据后才会发送停止位
发送起始位和地址位
在这里插入图片描述
首先查询IIC总线是否空闲 第一个while 然后发送一个起始位 然后查询是否发送成功第二个while 然后发送从机地址 |0x01是为了保证最后一位为1 表示是主机接收数据 从机发送数据 接收操作
发送从机地址前首先要清除AF标志位 然后发送地址
查询ADDR标志位查看是否寻址成功 如果寻址成功然后再查询AF标志位如果也等于1 那么说明寻址失败了 然后发送停止信号 结束 (往标志位STOP中写值发送停止信号) 等待总线空闲返回错误

接收数据 N=1

在这里插入图片描述
首先要清除ADDR标志位才可以传入数据

接受数据 N=2

在这里插入图片描述

接收数据 N>2

在这里插入图片描述
在这里插入图片描述
从倒数第三个数据开始 前N-3个数据都是一样的读取到缓冲区 然后到倒数第三个和倒数第二个数据进入RDR寄存器和移位寄存器 两个寄存器都满了然后标志位BTF为1 把两个数据都读取出来然后最后一个数据在传输进来的时候写入NCK和停止位结束数据的传输

测试

在这里插入图片描述
当熄灭显示器数据就是01000000 然后接收数据就是0x40 接收一个字节 接收两个字节就是两个0x40 接收八个字节就是8个0x40
亮起就都是0x00

#include "stm32f10x.h"
#include "stm32f10x_pal.h"static void App_I2C_Init(void);
static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size);
static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size); //接收数据int main(void)
{PAL_Init();App_I2C_Init();const uint8_t oled_init_command[] = {0x00, // Data Stream0xa8, 0x3f, // Set MUX Ratio0xd3, 0x00, // Set Display Offset 0x40, // Set Display Start Line0xa0, // Set Segment re-map0xc0, // Set COM Output Scan Direction0xda, 0x02, // Set COM Pins hardware configuration0x81, 0x7f, // Set Contrast Control0xa5, // Enable Entire Display On0xa6, // Set Normal Display0xd5, 0x80, // Set OSC Frequency0x8d, 0x14, // Enable charge pump regulator0xaf, // Display on}; App_I2C_MasterTransmit(0x78, oled_init_command, sizeof(oled_init_command)/sizeof(uint8_t));const uint8_t oled_display_off_command[] = {0x00, 0xae};const uint8_t oled_display_on_command[] = {0x00, 0xaf};uint8_t buffer[8];// 熄灭屏幕App_I2C_MasterTransmit(0x78, oled_display_off_command, sizeof(oled_display_off_command)/sizeof(uint8_t));App_I2C_MasterReceive(0x78, buffer, 1);App_I2C_MasterReceive(0x78, buffer, 2);App_I2C_MasterReceive(0x78, buffer, 8);App_I2C_MasterTransmit(0x78, oled_display_on_command, sizeof(oled_display_on_command)/sizeof(uint8_t));App_I2C_MasterReceive(0x78, buffer, 1);App_I2C_MasterReceive(0x78, buffer, 2);App_I2C_MasterReceive(0x78, buffer, 8);while(1){}
}static void App_I2C_Init(void)
{// #1. 初始化SCL和SDA引脚RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);// #2. 为I2C1开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);// #3. 配置I2C的参数I2C_InitTypeDef I2C_InitStruct;I2C_InitStruct.I2C_ClockSpeed = 400000;I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;// I2C_InitStruct.I2C_OwnAddress1 = 0x12;// I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;// I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Init(I2C1, &I2C_InitStruct);// #4. 使能I2CI2C_Cmd(I2C1, ENABLE);
}static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size)
{	// #1. 等待总线空闲while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);// #2. 发送起始位I2C_GenerateSTART(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);// #3. 发送从机地址I2C_ClearFlag(I2C1, I2C_FLAG_AF);I2C_SendData(I2C1, SlaveAddr & 0xfe);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);// #4. 发送数据uint32_t i;for(i=0;i<Size;i++){while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}I2C_SendData(I2C1, pData[i]);}while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}// #5. 发送停止位I2C_GenerateSTOP(I2C1, ENABLE);return SUCCESS;TAG_ERROR:I2C_GenerateSTOP(I2C1, ENABLE);return ERROR;
}static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size)
{if(Size == 0){return ERROR;}// #1. 等待总线空闲while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);// #2. 发送起始位I2C_GenerateSTART(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);	// #3. 发送从机地址I2C_ClearFlag(I2C1, I2C_FLAG_AF);I2C_SendData(I2C1, SlaveAddr | 0x01);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}// #4. 接收数据I2C_AcknowledgeConfig(I2C1, ENABLE);I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);if(Size == 1){I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);I2C_AcknowledgeConfig(I2C1, DISABLE);I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);I2C_GenerateSTOP(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);pDataOut[0] = I2C_ReceiveData(I2C1);}else if(Size == 2){I2C_AcknowledgeConfig(I2C1, ENABLE);I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);I2C_AcknowledgeConfig(I2C1, DISABLE);I2C_GenerateSTOP(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);pDataOut[0] = I2C_ReceiveData(I2C1);pDataOut[1] = I2C_ReceiveData(I2C1);}else{uint32_t i;I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);for(i=0;i<Size-3;i++){while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);pDataOut[i] = I2C_ReceiveData(I2C1);}while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);I2C_AcknowledgeConfig(I2C1, DISABLE);pDataOut[Size-3] = I2C_ReceiveData(I2C1);I2C_GenerateSTOP(I2C1, ENABLE);pDataOut[Size-2] = I2C_ReceiveData(I2C1);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);pDataOut[Size-1] = I2C_ReceiveData(I2C1);}return SUCCESS;
TAG_ERROR:I2C_GenerateSTOP(I2C1, ENABLE);return ERROR;
}

PAL库函数接口

在这里插入图片描述

#include "stm32f10x.h"
#include "stm32f10x_pal.h"
#include "stm32f10x_pal_i2c.h"static void App_I2C_Init(void);
static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size);
static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size); //接收数据
static PalI2C_HandleTypeDef hi2c1; //声明句柄使用PAL库IICint main(void)
{PAL_Init();//App_I2C_Init();hi2c1.Init.I2Cx = I2C1;hi2c1.Init.I2C_ClockSpeed = 400000;hi2c1.Init.I2C_DutyCycle = I2C_DutyCycle_2;PAL_I2C_Init(&hi2c1);const uint8_t oled_init_command[] = {0x00, // Data Stream0xa8, 0x3f, // Set MUX Ratio0xd3, 0x00, // Set Display Offset 0x40, // Set Display Start Line0xa0, // Set Segment re-map0xc0, // Set COM Output Scan Direction0xda, 0x02, // Set COM Pins hardware configuration0x81, 0x7f, // Set Contrast Control0xa5, // Enable Entire Display On0xa6, // Set Normal Display0xd5, 0x80, // Set OSC Frequency0x8d, 0x14, // Enable charge pump regulator0xaf, // Display on}; PAL_I2C_MasterTransmit(&hi2c1,0X78,oled_init_command,sizeof(oled_init_command)/sizeof(uint8_t));//App_I2C_MasterTransmit(0x78, oled_init_command, sizeof(oled_init_command)/sizeof(uint8_t));const uint8_t oled_display_off_command[] = {0x00, 0xae};const uint8_t oled_display_on_command[] = {0x00, 0xaf};uint8_t buffer[8];// 熄灭屏幕PAL_I2C_MasterTransmit(&hi2c1,0X78,oled_display_off_command,sizeof(oled_init_command)/sizeof(uint8_t));PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 1);PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 2);PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 8);App_I2C_MasterTransmit(0x78, oled_display_on_command, sizeof(oled_display_on_command)/sizeof(uint8_t));PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 1);PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 2);PAL_I2C_MasterReceive(&hi2c1,0X78,buffer, 8);while(1){}
}static void App_I2C_Init(void)
{// #1. 初始化SCL和SDA引脚RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStruct);// #2. 为I2C1开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);// #3. 配置I2C的参数I2C_InitTypeDef I2C_InitStruct;I2C_InitStruct.I2C_ClockSpeed = 400000;I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;// I2C_InitStruct.I2C_OwnAddress1 = 0x12;// I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;// I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;I2C_Init(I2C1, &I2C_InitStruct);// #4. 使能I2CI2C_Cmd(I2C1, ENABLE);
}static ErrorStatus App_I2C_MasterTransmit(uint8_t SlaveAddr, const uint8_t *pData, uint16_t Size)
{	// #1. 等待总线空闲while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);// #2. 发送起始位I2C_GenerateSTART(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);// #3. 发送从机地址I2C_ClearFlag(I2C1, I2C_FLAG_AF);I2C_SendData(I2C1, SlaveAddr & 0xfe);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);// #4. 发送数据uint32_t i;for(i=0;i<Size;i++){while(I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}I2C_SendData(I2C1, pData[i]);}while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}// #5. 发送停止位I2C_GenerateSTOP(I2C1, ENABLE);return SUCCESS;TAG_ERROR:I2C_GenerateSTOP(I2C1, ENABLE);return ERROR;
}static ErrorStatus App_I2C_MasterReceive(uint8_t SlaveAddr, uint8_t *pDataOut, uint16_t Size)
{if(Size == 0){return ERROR;}// #1. 等待总线空闲while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);// #2. 发送起始位I2C_GenerateSTART(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_SB) == RESET);	// #3. 发送从机地址I2C_ClearFlag(I2C1, I2C_FLAG_AF);I2C_SendData(I2C1, SlaveAddr | 0x01);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == RESET){if(I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET){goto TAG_ERROR;}}// #4. 接收数据I2C_AcknowledgeConfig(I2C1, ENABLE);I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);if(Size == 1){I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);I2C_AcknowledgeConfig(I2C1, DISABLE);I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Current);I2C_GenerateSTOP(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE)==RESET);pDataOut[0] = I2C_ReceiveData(I2C1);}else if(Size == 2){I2C_AcknowledgeConfig(I2C1, ENABLE);I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);I2C_AcknowledgeConfig(I2C1, DISABLE);I2C_GenerateSTOP(I2C1, ENABLE);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);pDataOut[0] = I2C_ReceiveData(I2C1);pDataOut[1] = I2C_ReceiveData(I2C1);}else{uint32_t i;I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);for(i=0;i<Size-3;i++){while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);pDataOut[i] = I2C_ReceiveData(I2C1);}while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BTF) == RESET);I2C_AcknowledgeConfig(I2C1, DISABLE);pDataOut[Size-3] = I2C_ReceiveData(I2C1);I2C_GenerateSTOP(I2C1, ENABLE);pDataOut[Size-2] = I2C_ReceiveData(I2C1);while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET);pDataOut[Size-1] = I2C_ReceiveData(I2C1);}return SUCCESS;
TAG_ERROR:I2C_GenerateSTOP(I2C1, ENABLE);return ERROR;
}

这篇关于pal库 IIC的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

【STM32+HAL库】---- 硬件IIC驱动0.96OLED

硬件开发板:STM32G0B1RET6软件平台:cubemax+keil+VScode 内容原著声明 代码借鉴学习于以下文章: STM32 使用硬件IIC驱动0.96寸4针IOLED显示器(HAL库) 1 新建cubemax工程 1.1 配置系统时钟RCC 1.2 配置引脚 1.3 导出工程 略… 2 代码 2.1 OLED_IIC_Config.h /*** **

STM32 IIC

第一块:介绍协议规则,然后用软件模拟的形式来实现协议, 第二块:介绍STM32的IIC外设,然后用硬件来实现协议 因为IIC是同步时序的额,软件模拟协议也非常方便,像我们单片机一样,外挂芯片里的众多外设也是通过读写寄存器来控制运行的,寄存器本身也是存储器的一种,,这个芯片多有的寄存器也是都被分配到了一个线性的存储空间,如果我们想要读写寄存器来控制硬件电路,我们就至少需要定义两个字节数据,一个字节

Linux-IIC驱动(3)-IIC用户态驱动程序设计

之前已经说过,有2种i2c驱动程序的设计,比如说针对EEPROM的驱动程序。我们可以专门编写一个针对EEPROM的驱动程序。另一种方式就是通过i2c-dev,即通过i2c通用通用驱动,来编写一个应用程序,来完成对设备的控制。   我们现在就来实现i2c用户态驱动程序的设计。 通用设备驱动分析 首先需要分析i2c-dev,先打开i2c-dev.c这个文件,找到i2c_dev_init函

Linux-IIC驱动(2)-Linux下IIC子系统的介绍

IIC子系统架构   Linux下IIC的架构模型大概可以分为3层: 第一层是IIC的从设备驱动,他包含图中的device driver和i2c-dev。device driver需要用户编写,i2c-dev由内核实现,包含了IIC设备的通用方法,但是用户不能直接使用这个驱动,需要编写一个用户层驱动,它们2个合起来才可以实现一个驱动程序。   第二层总线驱动,他又叫做控制器驱动

Linux-IIC驱动(1)-IIC总线介绍

IIC我在很久之前就接触并使用过了,现在来回顾一下它的硬件结构和时序   硬件结构 I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。硬件结构如下:   I2C总线只有两根双向信号线。 SDA: Serial Data Line-数据线 SCL :Serial Clock-时钟线   I2C总线

三、IIC总线协议——2、AT24C02

一、AT24C02介绍         EEPROM是一种掉电后数据不丢失的储存器,常用来存储一些配置信息,在系统重新上电时就可以加载。         AT24C02是一个2K bit的EEPROM存储器,使用IIC通信方式。         A0/1/2 : 设备地址决定引脚。、         WP : 写保护引脚。         SCL : 时钟线。         SDA

57.基于IIC协议的EEPROM驱动控制(4)

(1)顶层代码: module IIC_EEPROM(input wire clk ,input wire reset_n ,input wire key_r ,input wire key_w ,output

Xilinx FPGA Microblaze AXI_IIC使用方法及心得

Xilinx FPGA Microblaze AXI_IIC使用方法及心得 前言 本着好好学习,认真负责的态度,我计划在空闲时间把自己用到的一些模块的使用方法与心得总结下与大家分享下,技术交流的同时共同进步,如有问题,欢迎批评指正! 本次先着重讲下AXI_IIC核的使用,后续还会包括以下模块 UART_AXI核使用及AXI总线详解QSPI_AXI核的使用AXI_DMA与AXI_FIFO使用,

Linux驱动学习之IIC(驱动BH1750)

Linux内核IIC底层驱动,厂家已经写好了,我们需要做的是,修改设备树,调用他的驱动,添加我们设备的信息(在设备树中添加节点),对于初学者来讲,linux驱动学习最重要的不是学习linux内核,而是对设备树的学习(后面会出专题),可以说学会设备树规则,就已经成功了一办,剩下的就是了解API接口。 在设备树中添加设备节点 在根节点外修改I2C节点 (&+标签名==追加)原节点没有的会追

小实战项目-第二章2.3软件IIC 硬件IIC讲解 STM32 IIC通讯协议讲解

这篇章我们说明硬件IIC,软件IIC和相关基础知识在这文章里面 添加链接描述 https://blog.csdn.net/qq_46187594/article/details/141642801 2.3-硬件I2C 我们还使用第0章的工程 初始化硬件IIC 设置串口,方便输出调试 重映射 /*** @brief 重定向printf (重定向fputc),使用时候记得勾选