基于HAL库的STM32F4 + DMA方式I2C驱动的示例代码,可以读写两个PCA9555芯片,并且具有读写容错功能与操作PCA9555输出PIN脚电平功能。如果连续多次出现错误,代码将重新初始化PCA9555芯片:
时间: 2023-06-27 22:03:18 浏览: 560
以下是基于HAL库的STM32F4 + DMA方式I2C驱动的示例代码,可以读写两个PCA9555芯片,并且具有读写容错功能与操作PCA9555输出PIN脚电平功能。如果连续多次出现错误,代码将重新初始化PCA9555芯片:
```c
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"
#include <stdbool.h>
/* Private variables ---------------------------------------------------------*/
#define PCA9555_ADDR_0 0x40 // I2C address of PCA9555 #0
#define PCA9555_ADDR_1 0x42 // I2C address of PCA9555 #1
#define PCA9555_INPUT_PORT_REG 0x00 // Input port register address
#define PCA9555_OUTPUT_PORT_REG 0x02 // Output port register address
#define PCA9555_POLARITY_INVERSION_REG 0x04 // Polarity inversion register address
#define PCA9555_CONFIGURATION_REG 0x06 // Configuration register address
#define PCA9555_RESET_TRIES 10 // Number of times to reset PCA9555 before giving up
#define PCA9555_RESET_DELAY_MS 10 // Delay in ms between PCA9555 reset attempts
typedef struct {
uint8_t address;
bool initialized;
uint8_t output_port_state;
uint8_t read_tries;
uint8_t write_tries;
} PCA9555;
PCA9555 pca9555[2] = {
{PCA9555_ADDR_0, false, 0x00, 0, 0},
{PCA9555_ADDR_1, false, 0x00, 0, 0}
};
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* Private user code ---------------------------------------------------------*/
void PCA9555_Init(PCA9555 *pca) {
uint8_t data[] = {PCA9555_CONFIGURATION_REG, 0x00}; // Configure all pins as outputs
HAL_I2C_Master_Transmit_DMA(&hi2c1, pca->address, data, sizeof(data));
HAL_Delay(5);
pca->initialized = true;
}
uint8_t PCA9555_Read_Input_Port(PCA9555 *pca) {
uint8_t data = 0x00;
if (HAL_I2C_Master_Transmit_DMA(&hi2c1, pca->address, &PCA9555_INPUT_PORT_REG, sizeof(PCA9555_INPUT_PORT_REG)) == HAL_OK
&& HAL_I2C_Master_Receive_DMA(&hi2c1, pca->address, &data, sizeof(data)) == HAL_OK) {
pca->read_tries = 0;
return data;
}
else {
pca->read_tries++;
if (pca->read_tries >= PCA9555_RESET_TRIES) {
pca->initialized = false;
PCA9555_Init(pca);
}
return 0xFF;
}
}
bool PCA9555_Write_Output_Port(PCA9555 *pca, uint8_t data) {
if (HAL_I2C_Master_Transmit_DMA(&hi2c1, pca->address, &(uint8_t){PCA9555_OUTPUT_PORT_REG}, sizeof(PCA9555_OUTPUT_PORT_REG)) == HAL_OK
&& HAL_I2C_Master_Transmit_DMA(&hi2c1, pca->address, &data, sizeof(data)) == HAL_OK) {
pca->write_tries = 0;
pca->output_port_state = data;
return true;
}
else {
pca->write_tries++;
if (pca->write_tries >= PCA9555_RESET_TRIES) {
pca->initialized = false;
PCA9555_Init(pca);
}
return false;
}
}
void PCA9555_Set_Pin_Level(PCA9555 *pca, uint8_t pin, bool level) {
uint8_t data = pca->output_port_state;
if (level) {
data |= (1 << pin);
}
else {
data &= ~(1 << pin);
}
PCA9555_Write_Output_Port(pca, data);
}
/* Main function -------------------------------------------------------------*/
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* Infinite loop */
while (1)
{
for (int i = 0; i < 2; i++) {
if (!pca9555[i].initialized) {
PCA9555_Init(&pca9555[i]);
}
uint8_t input_port_state = PCA9555_Read_Input_Port(&pca9555[i]);
if (input_port_state != 0xFF) {
uint8_t output_port_state = pca9555[i].output_port_state;
for (int j = 0; j < 8; j++) {
bool input_pin_state = input_port_state & (1 << j);
bool output_pin_state = output_port_state & (1 << j);
if (input_pin_state != output_pin_state) {
PCA9555_Set_Pin_Level(&pca9555[i], j, input_pin_state);
}
}
}
}
HAL_Delay(10);
}
}
/* System Clock Configuration--------------------------------------------------*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
```
在此示例代码中,我们定义了一个名为PCA9555的结构体来存储与PCA9555芯片相关的信息。其中包括I2C地址、是否已初始化、输出端口状态、读取失败次数和写入失败次数。我们还定义了两个PCA9555结构体实例pca9555[0]和pca9555[1],分别代表两个PCA9555芯片。在main函数中,我们使用了一个无限循环,不断读取和写入两个PCA9555芯片。
在PCA9555_Init函数中,我们配置了所有引脚作为输出。在PCA9555_Read_Input_Port函数中,我们尝试读取输入端口寄存器的值,并返回读取的值。如果读取失败,则增加读取失败次数。如果读取失败次数达到了PCA9555_RESET_TRIES,则将initialized标志设置为false,并重新初始化PCA9555芯片。在PCA9555_Write_Output_Port函数中,我们尝试写入数据到输出端口寄存器,并返回写入是否成功的布尔值。如果写入失败,则增加写入失败次数。如果写入失败次数达到了PCA9555_RESET_TRIES,则将initialized标志设置为false,并重新初始化PCA9555芯片。在PCA9555_Set_Pin_Level函数中,我们根据传递的引脚和电平设置输出端口的状态。
最后,在main函数的无限循环中,我们轮流读取和写入两个PCA9555芯片,如果出现错误,则尝试重新初始化PCA9555芯片。我们使用HAL_Delay函数来添加延迟,以避免频繁读写I2C总线。