一、引脚介绍
1.引脚图
2.引脚描述
二、功能介绍
熟悉AT9531的寄存器
1.当作输入口,读取I/O口的电平
2.当作输出口,输出高低电平
3.输出不同频率和占空比的PWM波
三、采用STM32F407的HAL库,与AT9531实现软件IIC通信
IIC.C
/*
* softiic.c
*
* Created on: 2024年6月12日
* Author: Administrator
*/
#include "softiic.h"
uint8_t send_data[]={0x01,0x02,0x03,0x04,0x05,0x06};
uint8_t receive_data[]={0x00,0x00,0x00,0x00,0x00,0x00};
uint32_t delay1us;
/**
* @brief: 1us延时
* @param {uint32_t} delay_1us
* @return {*}
*/
void delay_1us(uint32_t delay_1us)
{
__IO uint32_t Delay = delay_1us * 168 / 8;//(SystemCoreClock / 8U / 1000000U)
//见stm32f1xx_hal_rcc.c -- static void RCC_Delay(uint32_t mdelay)
do
{
__NOP();
}
while (Delay --);
}
/**
* @brief: IIC延时时间
* @return {*}
*/
void analog_i2c_delay(void)
{
delay_1us(5);
}
/**
* @brief: 软件模拟I2C初始化
* @return {*}
*/
void bsp_analog_i2c_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pins : PD6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/*Configure GPIO pins : PC1 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
i2c_sda_high();
i2c_scl_high();
// bsp_analog_i2c_stop();
}
/**
* @brief: I2C 开始,SCL为高电平的时候SDA产生一个下降沿信号
* @return {*}
*/
void bsp_analog_i2c_start(void)
{
/* _____
*SDA \_____________
* __________
*SCL \________
*/
SDA_OUT();
i2c_sda_high();
i2c_scl_high();
analog_i2c_delay();
i2c_sda_low();
analog_i2c_delay();
i2c_scl_low();
analog_i2c_delay();
}
/**
* @brief: I2C 停止,SCL为高电平的时候SDA产生一个上升沿信号
* @return {*}
*/
void bsp_analog_i2c_stop(void)
{
/* _______
*SDA __________/
* ____________
*SCL _____/
*/
SDA_OUT();
i2c_sda_low();
i2c_scl_high();
analog_i2c_delay();
i2c_sda_high();
analog_i2c_delay();
}
/**
* @brief: I2C 等待响应
* @return {*}
*/
uint8_t bsp_analog_i2c_wait_ack(void)
{
uint32_t timeout = 0;
i2c_sda_high();
SDA_IN();
analog_i2c_delay();
i2c_scl_high();
analog_i2c_delay();
while(i2c_read_sda())
{
timeout++;
if(timeout > 255)
{
bsp_analog_i2c_stop();
return 1;
}
//printf("timeout=%d\r\n",timeout);
}
i2c_scl_low();
analog_i2c_delay();
return 0;
}
/**
* @brief: I2C 响应
* @return {*}
*/
void bsp_analog_i2c_ack(void)
{
/* ____
*SCL ______/ \______
* ____ _____
*SDA \_______/
*/
SDA_OUT();
i2c_sda_low();
analog_i2c_delay();
i2c_scl_high();
analog_i2c_delay();
i2c_scl_low();
analog_i2c_delay();
i2c_sda_high();
}
/**
* @brief: I2C 不响应
* @return {*}
*/
void bsp_analog_i2c_nack(void)
{
/* ____
*SCL ______/ \______
* __________________
*SDA
*/
SDA_OUT();
i2c_sda_high();
analog_i2c_delay();
i2c_scl_high();
analog_i2c_delay();
i2c_scl_low();
analog_i2c_delay();
}
/**
* @brief: I2C 发送一个字节数据
* @param {uint8_t} data
* @return {*}
*/
void bsp_analog_i2c_send_byte(uint8_t data)
{
uint8_t i;
SDA_OUT();
for(i = 0; i < 8; i++)
{
if(data & 0x80)
{
i2c_sda_high();
}
else
{
i2c_sda_low();
}
analog_i2c_delay();
i2c_scl_high();
analog_i2c_delay();
i2c_scl_low();
if(i == 7)
{
i2c_sda_high();
}
data <<= 1;
analog_i2c_delay();
}
}
/**
* @brief: I2C 读一个字节数据
* @return {*}
*/
uint8_t bsp_analog_i2c_read_byte(void)
{
uint8_t i, data = 0;
i2c_sda_high();
SDA_IN();
for(i = 0; i < 8; i++ )
{
data <<= 1;
i2c_scl_high();
analog_i2c_delay();
if(i2c_read_sda())
{
data++;
}
i2c_scl_low();
analog_i2c_delay();
}
return data;
}
void WriteOneByte(uint8_t WriteAddr,uint8_t DataToWrite)
{
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_write);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_send_byte(WriteAddr);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_send_byte(DataToWrite);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_stop();
}
uint8_t ReadOneByte(uint8_t ReadAddr)
{
uint8_t temp=0;
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_write);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_send_byte(ReadAddr);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_read);
bsp_analog_i2c_wait_ack();
temp= bsp_analog_i2c_read_byte();
bsp_analog_i2c_nack();
bsp_analog_i2c_stop();
return temp;
}
/*连续写*/
void sequence_write(uint8_t WriteAddr,uint8_t* data,int length)
{
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_write);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_send_byte(WriteAddr);
bsp_analog_i2c_wait_ack();
for (int i = 0; i < length; i++)
{
bsp_analog_i2c_send_byte(*(data+i));
bsp_analog_i2c_wait_ack();
}
bsp_analog_i2c_nack();
bsp_analog_i2c_stop();
}
/*连续读*/
void sequence_read(uint8_t ReadAddr,uint8_t *data,int length)
{
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_write);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_send_byte(ReadAddr);
bsp_analog_i2c_wait_ack();
bsp_analog_i2c_start();
bsp_analog_i2c_send_byte(salve_address_read);
bsp_analog_i2c_wait_ack();
for (int i = 0; i < length; i++)
{
*(data+i)= bsp_analog_i2c_read_byte();
bsp_analog_i2c_ack();
}
bsp_analog_i2c_stop();
}
IIC.H
/*
* softiic.h
*
* Created on: 2024年6月12日
* Author: Administrator
*/
#ifndef __SOFTIIC_H_
#define __SOFTIIC_H_
#include "main.h"
//使用IICX PD6,PC1
#define salve_address_write 0xC0
#define salve_address_read 0xC1
#define SDA_IN() {GPIOC->MODER &= ~(3 << 1 * 2);GPIOC->MODER = (0 << 1 * 2);}
#define SDA_OUT() {GPIOC->MODER &= ~(3 << 1 * 2);GPIOC->MODER = (1 << 1 * 2);}
//void SDAIN(void);
//IO操作函数
#define i2c_scl_low() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_RESET)
#define i2c_scl_high() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_6, GPIO_PIN_SET)
#define i2c_sda_low() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET)
#define i2c_sda_high() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET)
#define i2c_read_sda() HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1)
extern uint32_t delay1us;
void delay_1us(uint32_t delay_1us);
void analog_i2c_delay(void);
void bsp_analog_i2c_init(void);
void bsp_analog_i2c_start(void);
void bsp_analog_i2c_stop(void);
uint8_t bsp_analog_i2c_wait_ack(void);
void bsp_analog_i2c_ack(void);
void bsp_analog_i2c_nack(void);
void bsp_analog_i2c_send_byte(uint8_t data);
uint8_t bsp_analog_i2c_read_byte(void);
void WriteOneByte(uint8_t WriteAddr,uint8_t DataToWrite);
uint8_t ReadOneByte(uint8_t ReadAddr);
void sequence_write(uint8_t WriteAddr,uint8_t* data,int length);
void sequence_read(uint8_t ReadAddr,uint8_t data[],int length);
#endif
四、AT9531的驱动
AT9531.C
/*
* AT9531.c
*
* Created on: 2024年6月14日
* Author: Administrator
*/
#include "AT9531.h"
#include <stdio.h>
#include <stdlib.h>
#include "softiic.h"
#include "stdint.h"
/*上电的时候,将每个寄存器进行清零*/
void AT9531_clear(void)
{
WriteOneByte(PCA9531_REG_IN, clear);
WriteOneByte(PCA9531_REG_PSC0, clear);
WriteOneByte(PCA9531_REG_PWM0, clear);
WriteOneByte(PCA9531_REG_PSC1, clear);
WriteOneByte(PCA9531_REG_PWM1, clear);
WriteOneByte(PCA9531_REG_LS0, clear);
WriteOneByte(PCA9531_REG_LS1, clear);
}
/**
* @brief 获取I/O口的状态
* @param GPIO_X可以是GPIO_0-GPIO_7
* @retval 返回值是GPIO的状态
*/
//get_gpio_status(GPIO_1)
uint8_t get_gpio_status(uint8_t GPIO_X)
{
uint8_t register_original_data = 0;
uint8_t gpio_status = 0;
register_original_data=ReadOneByte(0x00);
switch(GPIO_X)
{
case 0x01: gpio_status = register_original_data & GPIO_X;break;
case 0x02: gpio_status = (register_original_data & GPIO_X) >> 1;break;
case 0x04: gpio_status = (register_original_data & GPIO_X) >> 2;break;
case 0x08: gpio_status = (register_original_data & GPIO_X) >> 3;break;
case 0x10: gpio_status = (register_original_data & GPIO_X) >> 4;break;
case 0x20: gpio_status = (register_original_data & GPIO_X) >> 5;break;
case 0x40: gpio_status = (register_original_data & GPIO_X) >> 6;break;
case 0x80: gpio_status = (register_original_data & GPIO_X) >> 7;break;
default: printf("[ERROR] gpio_input error!\r\n");
}
return gpio_status;
}
/**
* @brief 设置I/O口输出波形
* @param GPIO_X可以是GPIO_0-GPIO_7
* @param Mode可以是Output_high_impedance、Output_low、Output_pwm0、Output_pwm1
* @param Psc可以设定频率 The period of BLINK = (Psc + 1) / 152 0-152HZ
* @param Pwm可以设定占空比 The duty cycle of BLINK = Pwm / 256 0-256
* @retval 0
*/
void gpio_output_pwm(uint8_t GPIO_X,uint8_t Psc,uint8_t Pwm)
{
switch(GPIO_X)
{
case 0x01: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_pwm);break;
case 0x02: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED1_pwm);break;
case 0x04: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED2_pwm);break;
case 0x08: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED3_pwm);break;
case 0x10: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_pwm);break;
case 0x20: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED5_pwm);break;
case 0x40: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED6_pwm);break;
case 0x80: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED7_pwm);break;
case 0x0f: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_LED3_pwm);break;
case 0xf0: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_LED7_pwm);break;
default: printf("[ERROR] gpio_output error!\r\n");
}
if(GPIO_X==GPIO_0||GPIO_X==GPIO_1||GPIO_X==GPIO_2||GPIO_X==GPIO_3||GPIO_X==GPIO_0_3)
{
WriteOneByte(PCA9531_REG_PSC0, Psc);
WriteOneByte(PCA9531_REG_PWM0, Pwm);
}
else if(GPIO_X==GPIO_4||GPIO_X==GPIO_5||GPIO_X==GPIO_6||GPIO_X==GPIO_7||GPIO_X==GPIO_4_7)
{
WriteOneByte(PCA9531_REG_PSC1, Psc);
WriteOneByte(PCA9531_REG_PWM1, Pwm);
}
}
/*
* 0.59357-152 任意频率
0-100 占空比设定
*/
void gpio_output_randompwm(uint8_t GPIO_X,uint8_t Freq,uint8_t Duty)
{
float Psc=0;
float Pwm=0;
Psc=152/Freq-1;
Pwm=256*(1-Duty*0.01);
switch(GPIO_X)
{
case 0x01: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_pwm);break;
case 0x02: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED1_pwm);break;
case 0x04: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED2_pwm);break;
case 0x08: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED3_pwm);break;
case 0x10: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_pwm);break;
case 0x20: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED5_pwm);break;
case 0x40: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED6_pwm);break;
case 0x80: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED7_pwm);break;
case 0x0f: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_LED3_pwm);break;
case 0xf0: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_LED7_pwm);break;
default: printf("[ERROR] gpio_output error!\r\n");
}
if(GPIO_X==GPIO_0||GPIO_X==GPIO_1||GPIO_X==GPIO_2||GPIO_X==GPIO_3||GPIO_X==GPIO_0_3)
{
WriteOneByte(PCA9531_REG_PSC0, Psc);
WriteOneByte(PCA9531_REG_PWM0, Pwm);
}
else if(GPIO_X==GPIO_4||GPIO_X==GPIO_5||GPIO_X==GPIO_6||GPIO_X==GPIO_7||GPIO_X==GPIO_4_7)
{
WriteOneByte(PCA9531_REG_PSC1, Psc);
WriteOneByte(PCA9531_REG_PWM1, Pwm);
}
}
/*将I/O口设置为低电平*/
void gpio_output_low(uint8_t GPIO_X)
{
switch(GPIO_X)
{
case 0x01: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED0_low);break;
case 0x02: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED1_low);break;
case 0x04: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED2_low);break;
case 0x08: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED3_low);break;
case 0x10: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED4_low);break;
case 0x20: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED5_low);break;
case 0x40: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED6_low);break;
case 0x80: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED7_low);break;
case 0x0f: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_3_low);break;
case 0xf0: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_7_low);break;
default: printf("[ERROR] gpio_output error!\r\n");
}
}
/*将I/O口设置为高阻态*/
void gpio_output_highimpedance(uint8_t GPIO_X)
{
switch(GPIO_X)
{
case 0x01: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED0_highimpedance);break;
case 0x02: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED1_highimpedance);break;
case 0x04: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED2_highimpedance);break;
case 0x08: WriteOneByte(PCA9531_REG_LS0,ReadOneByte(PCA9531_REG_LS0)| LED3_highimpedance);break;
case 0x10: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED4_highimpedance);break;
case 0x20: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED5_highimpedance);break;
case 0x40: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED6_highimpedance);break;
case 0x80: WriteOneByte(PCA9531_REG_LS1,ReadOneByte(PCA9531_REG_LS1)| LED7_highimpedance);break;
case 0x0f: WriteOneByte(PCA9531_REG_LS0, ReadOneByte(PCA9531_REG_LS0)|LED0_3_highimpedance);break;
case 0xf0: WriteOneByte(PCA9531_REG_LS1, ReadOneByte(PCA9531_REG_LS1)|LED4_7_highimpedance);break;
default: printf("[ERROR] gpio_output error!\r\n");
}
}
AT9531.H
/*
* AT9531.h
*
* Created on: 2024年6月14日
* Author: Administrator
*/
#ifndef INC_AT9531_H_
#define INC_AT9531_H_
#include "AT9531.h"
#include <stdlib.h>
#include <stdio.h>
/********************* 定义PCA9531的寄存器地址 ***********************/
#define PCA9531_REG_IN 0x00 //输入寄存器地址
#define PCA9531_REG_PSC0 0x01 //频率寄存器0地址
#define PCA9531_REG_PWM0 0x02 //占空比寄存器0地址
#define PCA9531_REG_PSC1 0x03 //频率寄存器0地址
#define PCA9531_REG_PWM1 0x04 //占空比寄存器0地址
#define PCA9531_REG_LS0 0x05 //选择寄存器0地址
#define PCA9531_REG_LS1 0x06 //选择寄存器1地址
#define clear 0x00
typedef enum
{ GPIO_0 = 0x01,
GPIO_1 = 0x02,
GPIO_2 = 0x04,
GPIO_3 = 0x08,
GPIO_4 = 0x10,
GPIO_5 = 0x20,
GPIO_6 = 0x40,
GPIO_7 = 0x80,
GPIO_0_3=0x0f,//一次性设置0-3
GPIO_4_7=0xf0//一次性设置4-7
}GPIO_Num;
typedef enum
{ Output_high_impedance = 0x00,
Output_low = 0x01,
Output_pwm0 = 0x02,
Output_pwm1 = 0x03,
}GPIO_Mode;
typedef enum
{ Output_Freq_152HZ = 0x00,
Output_Freq_76HZ = 0X01,
Output_Freq_38HZ = 0X03,
Output_Freq_19HZ = 0X07
}GPIO_Psc;
typedef enum
{
Output_Pwm_25dutycycle = 0xc0,
Output_Pwm_50dutycycle = 0x80,
Output_Pwm_75dutycycle = 0x40
}GPIO_Pwm;
typedef enum
{
LED0_pwm = 0x02,
LED1_pwm = 0x08,
LED2_pwm = 0X20,
LED3_pwm = 0x80,
LED4_pwm = 0x03,
LED5_pwm = 0x0c,
LED6_pwm = 0x30,
LED7_pwm = 0xc0,
LED0_LED3_pwm=0xAA,
LED4_LED7_pwm=0Xff
}GPIO_Pwm_Select;
typedef enum
{
LED0_low = 0x01,
LED1_low = 0x04,
LED2_low = 0X10,
LED3_low = 0x40,
LED4_low = 0x01,
LED5_low = 0x04,
LED6_low = 0x10,
LED7_low = 0x40,
LED0_3_low = 0x55,
LED4_7_low = 0x55,
}GPIO_Low_Select;
typedef enum
{
LED0_highimpedance = 0x00,
LED1_highimpedance = 0x00,
LED2_highimpedance = 0X00,
LED3_highimpedance = 0x00,
LED4_highimpedance = 0x00,
LED5_highimpedance = 0x00,
LED6_highimpedance = 0x00,
LED7_highimpedance = 0x00,
LED0_3_highimpedance = 0x00,
LED4_7_highimpedance = 0x00
}GPIO_Highimpedance_Select;
void AT9531_clear(void);
uint8_t get_gpio_status(uint8_t GPIO_X);
void gpio_output_pwm(uint8_t GPIO_X,uint8_t Psc,uint8_t Pwm);
void gpio_output_low(uint8_t GPIO_X);
void gpio_output_highimpedance(uint8_t GPIO_X);
void gpio_output_randompwm(uint8_t GPIO_X,uint8_t Freq,uint8_t Duty);
#endif /* INC_AT9531_H_ */