不用它的I2C设置,容易出错不通讯,只打开GPIO输出就可以;
如果是RTOS的话请打开系统定时器提供参考时间基准,那个定时器都行;
以下是经过验证的代码,同样适用于SGM同类系列电源管理芯片;
准备好jlink进行RTT打印观测:
SGM41511.c
/******************************************************************************
* Description : SGM41511 电源管理芯片驱动
* Author :
* Date : 2021.01.22
******************************************************************************/
#include "SGM41511.h"
#include "SEGGER_RTT.h"
/*******************************************************************************
* Function Name : delay_us
* Description : us延时
* Input : None
* Output : None
* Return : None
******************************************************************************/
void delay_us(unsigned short time)
{
unsigned short i = 0;
while(time--)
{
i = 100;
while(i--);
}
}
/*******************************************************************************
* Function Name : SGM41511_IIC_Init
* Description : IIC初始化
* Input : None
* Output : None
* Return : None
******************************************************************************/
void SGM41511_IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 使能GPIOB时钟 */
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/* 配置SCL和SDA引脚 */
GPIO_InitStruct.Pin = SCL_PIN | SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* 配置BAT_NCS引脚 */
GPIO_InitStruct.Pin = BAT_NCS_PIN|BAT_Psel_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
/* 初始化SCL和SDA为低电平 */
SCL_H();
SDA_H();
BAT_NCS_L();
// BAT_Psel_L();
SEGGER_RTT_printf(0,"SGM41511_IIC_Init!\n");
}
/*******************************************************************************
* Function Name : IIC_Sda_Mod
* Description : SDA输入输出选择
* Input : mod - SDA输入输出选择
* Output : None
* Return : None
******************************************************************************/
void IIC_Sda_Mod(unsigned char mod)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* 配置SCL引脚 */
GPIO_InitStruct.Pin = SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
if(mod != 0) // mod = 1, SDA输出模式
{
GPIO_InitStruct.Pin = SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
}
else // mod = 0, SDA输入模式
{
GPIO_InitStruct.Pin = SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
}
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
/*******************************************************************************
* Function Name : IIC_Start
* Description : 产生IIC起始信号
* Input : None
* Output : None
* Return : None
******************************************************************************/
void IIC_Start(void)
{
IIC_Sda_Mod(1); // SDA设置为输出
SCL_H();
SDA_H();
delay_us(4);
SDA_L();
delay_us(4);
SCL_L();
}
/*******************************************************************************
* Function Name : IIC_Stop
* Description : 产生IIC停止信号
* Input : None
* Output : None
* Return : None
******************************************************************************/
void IIC_Stop(void)
{
IIC_Sda_Mod(1); // SDA设置为输出
SCL_L();
SDA_L();
delay_us(4);
SCL_H();
SDA_H();
delay_us(4);
}
/*******************************************************************************
* Function Name : IIC_Wait_Ack
* Description : 等待应答信号到来
* Input : None
* Output : None
* Return : 0 - 接收应答成功, 1 - 接收应答失败
******************************************************************************/
unsigned char IIC_Wait_Ack(void)
{
unsigned char ucErrTime = 0;
IIC_Sda_Mod(0); // SDA设置为输入
SDA_H();
delay_us(1);
SCL_H();
delay_us(1);
while(HAL_GPIO_ReadPin(IIC_PORT, SDA_PIN))
{
ucErrTime++;
if(ucErrTime > 250)
{
IIC_Stop();
return 1;
}
}
SCL_L();
return 0;
}
/*******************************************************************************
* Function Name : IIC_Ack
* Description : 产生IIC应答信号
* Input : None
* Output : None
* Return : None
******************************************************************************/
void IIC_Ack(void)
{
SCL_L();
IIC_Sda_Mod(1); // SDA设置为输出
SDA_L();
delay_us(2);
SCL_H();
delay_us(2);
SCL_L();
}
/*******************************************************************************
* Function Name : IIC_NAck
* Description : 产生IIC非应答信号
* Input : None
* Output : None
* Return : None
******************************************************************************/
void IIC_NAck(void)
{
SCL_L();
IIC_Sda_Mod(1); // SDA设置为输出
SDA_H();
delay_us(2);
SCL_H();
delay_us(2);
SCL_L();
}
/*******************************************************************************
* Function Name : IIC_Send_Byte
* Description : IIC发送一个字节
* Input : txd - 要发送的字节
* Output : None
* Return : None
******************************************************************************/
void IIC_Send_Byte(unsigned char txd)
{
unsigned char t;
IIC_Sda_Mod(1); // SDA设置为输出
SCL_L();
for(t = 0; t < 8; t++)
{
if((txd & 0x80) >> 7)
SDA_H();
else
SDA_L();
txd <<= 1;
delay_us(2);
SCL_H();
delay_us(2);
SCL_L();
delay_us(2);
}
}
/*******************************************************************************
* Function Name : IIC_Read_Byte
* Description : IIC读取一个字节
* Input : ack - 是否发送ACK
* Output : None
* Return : 读取到的字节
******************************************************************************/
unsigned char IIC_Read_Byte(unsigned char ack)
{
unsigned char i, receive = 0;
IIC_Sda_Mod(0); // SDA设置为输入
for(i = 0; i < 8; i++)
{
SCL_L();
delay_us(2);
SCL_H();
receive <<= 1;
if(HAL_GPIO_ReadPin(IIC_PORT, SDA_PIN))
{
receive++;
}
delay_us(1);
}
if(!ack)
IIC_NAck();
else
IIC_Ack();
return receive;
}
/*******************************************************************************
* Function Name : SgmWriteByte
* Description : IIC写一个字节
* Input : reg - 寄存器地址, data - 要写入的数据
* Output : None
* Return : 0 - 正常, 1 - 错误
******************************************************************************/
unsigned char SgmWriteByte(unsigned char reg, unsigned char data)
{
IIC_Start();
IIC_Send_Byte(SGM_WRITE_ADDR); // 发送写命令
if(IIC_Wait_Ack())
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); // 写寄存器地址
IIC_Wait_Ack();
IIC_Send_Byte(data);
if(IIC_Wait_Ack())
{
IIC_Stop();
return 1;
}
IIC_Stop();
return 0;
}
/*******************************************************************************
* Function Name : SgmReadByte
* Description : IIC读取一个字节
* Input : reg - 寄存器地址
* Output : None
* Return : 读到的数据
******************************************************************************/
unsigned char SgmReadByte(unsigned char reg)
{
unsigned char temp1;
IIC_Start();
IIC_Send_Byte(SGM_WRITE_ADDR); // 发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(reg); // 写寄存器地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(SGM_READ_ADDR); // 发送读命令
IIC_Wait_Ack();
temp1 = IIC_Read_Byte(0);
IIC_Stop();
SEGGER_RTT_printf(0, "SgmReadByte: Reg 0x%02X = 0x%02X\n", reg, temp1);
return temp1;
}
/*******************************************************************************
* Function Name : SgmReadLen
* Description : IIC连续读取
* Input : reg - 寄存器地址, len - 要读取的长度, buf - 读取到的数据存储缓冲区
* Output : None
* Return : 0 - 正常, 1 - 错误
******************************************************************************/
unsigned char SgmReadLen(unsigned char reg, unsigned char len, unsigned char *buf)
{
IIC_Start();
IIC_Send_Byte(SGM_WRITE_ADDR); // 发送写命令
if(IIC_Wait_Ack())
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); // 写寄存器地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(SGM_READ_ADDR); // 发送读命令
IIC_Wait_Ack();
while(len)
{
if(len == 1)
*buf = IIC_Read_Byte(0);
else
*buf = IIC_Read_Byte(1);
len--;
buf++;
}
IIC_Stop();
return 0;
}
/*******************************************************************************
* Function Name : SGM41511_ReadAllRegisters
* Description : Reads all registers from REG00 to REG0B
* Input : None
* Output : None
* Return : None
******************************************************************************/
void SGM41511_ReadAllRegisters(void)
{
unsigned char reg_values[12];
for (int i = 0; i <= 0x0B; i++)
{
reg_values[i] = SgmReadByte(i);
SEGGER_RTT_printf(0, "REG%02X: 0x%02X (0B:", i, reg_values[i]);
// Print binary representation
for (int j = 7; j >= 0; j--)
{
SEGGER_RTT_printf(0, "%d", (reg_values[i] >> j) & 1);
}
SEGGER_RTT_printf(0, ")\n");
}
}
void SGM41511_WriteReg00(uint8_t value)
{
if (SgmWriteByte(REG00_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG00\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG00\n");
}
}
void SGM41511_WriteReg01(uint8_t value)
{
if (SgmWriteByte(REG01_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG01\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG01\n");
}
}
void SGM41511_WriteReg07(uint8_t value)
{
if (SgmWriteByte(REG07_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG07\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG07\n");
}
}
void SGM41511_WriteReg06(uint8_t value)
{
if (SgmWriteByte(REG06_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG06\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG06\n");
}
}
void SGM41511_WriteReg05(uint8_t value)
{
if (SgmWriteByte(REG05_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG05\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG05\n");
}
}
void SGM41511_WriteReg04(uint8_t value)
{
if (SgmWriteByte(REG04_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG04\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG04\n");
}
}
void SGM41511_WriteReg03(uint8_t value)
{
if (SgmWriteByte(REG03_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG03\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG03\n");
}
}
void SGM41511_WriteReg02(uint8_t value)
{
if (SgmWriteByte(REG02_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG02\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG02\n");
}
}
void SGM41511_WriteReg0B(uint8_t value)
{
if (SgmWriteByte(REG0B_ADDR, value) == 0)
{
SEGGER_RTT_printf(0, "Successfully wrote 0x%02X to REG0B\n", value);
}
else
{
SEGGER_RTT_printf(0, "Failed to write to REG0B\n");
}
}
SGM41511. h
/******************************************************************************
*Description :SGM41511 电源管理芯片驱动
*Author :
*Date :2021.01.22
*******************************************************************************/
#ifndef _SGM41511_H_
#define _SGM41511_H_
#include <stdint.h>
#include "main.h"
#include "stm32l4xx_hal.h"
#define SCL_PIN GPIO_PIN_8
#define SDA_PIN GPIO_PIN_9
#define IIC_PORT GPIOB
#define BAT_NCS_PIN GPIO_PIN_11
#define BAT_NCS_PORT GPIOE
#define BAT_Psel_PIN GPIO_PIN_10
#define BAT_Psel_PORT GPIOE
#define SGM_DEVICE_ADDR 0x6B
#define SGM_WRITE_ADDR ((SGM_DEVICE_ADDR<<1) | 0) // 0X6B <<1 0xD6
#define SGM_READ_ADDR ((SGM_DEVICE_ADDR<<1) | 1) // (0X6B << 1) + 1 0xD7
#define REG00_ADDR 0x00
REG00 (地址0x00):
//控制输入电流限制(IINDPM)
//使能/禁用HIZ模式
//控制STAT引脚功能
#define REG01_ADDR 0x01
#define REG02_ADDR 0x02
#define REG03_ADDR 0x03
#define REG04_ADDR 0x04
#define REG05_ADDR 0x05
#define REG06_ADDR 0x06
#define REG07_ADDR 0x07
#define REG08_ADDR 0x08
#define REG09_ADDR 0x09
#define REG0A_ADDR 0x0A
#define REG0B_ADDR 0x0B
//REG0B (0x14):
//包含芯片ID信息,0x14可能表示这是SGM41511芯片。
#define SDA_H() HAL_GPIO_WritePin(IIC_PORT, SDA_PIN, GPIO_PIN_SET)
#define SDA_L() HAL_GPIO_WritePin(IIC_PORT, SDA_PIN, GPIO_PIN_RESET)
#define SCL_H() HAL_GPIO_WritePin(IIC_PORT, SCL_PIN, GPIO_PIN_SET)
#define SCL_L() HAL_GPIO_WritePin(IIC_PORT, SCL_PIN, GPIO_PIN_RESET)
#define BAT_NCS_H() HAL_GPIO_WritePin(BAT_NCS_PORT, BAT_NCS_PIN, GPIO_PIN_SET)
#define BAT_NCS_L() HAL_GPIO_WritePin(BAT_NCS_PORT, BAT_NCS_PIN, GPIO_PIN_RESET)
#define BAT_Psel_H() HAL_GPIO_WritePin(BAT_Psel_PORT, BAT_Psel_PIN, GPIO_PIN_SET)
#define BAT_Psel_L() HAL_GPIO_WritePin(BAT_Psel_PORT, BAT_Psel_PIN, GPIO_PIN_RESET)
void SGM41511_IIC_Init(void);
void IIC_Sda_Mod(unsigned char mod);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(unsigned char txd);
unsigned char IIC_Read_Byte(unsigned char ack);
unsigned char IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
unsigned char SgmWriteByte(unsigned char reg,unsigned char data);
unsigned char SgmReadByte(unsigned char reg);
unsigned char SgmReadLen(unsigned char reg,unsigned char len,unsigned char *buf);
void SGM41511_ReadAllRegisters(void);
void SGM41511_WriteReg00(uint8_t value);
void SGM41511_WriteReg01(uint8_t value);
void SGM41511_WriteReg07(uint8_t value);
void SGM41511_WriteReg06(uint8_t value);
void SGM41511_WriteReg05(uint8_t value);
void SGM41511_WriteReg04(uint8_t value);
void SGM41511_WriteReg03(uint8_t value);
void SGM41511_WriteReg02(uint8_t value);
void SGM41511_WriteReg0B(uint8_t value);
#endif
移植的话你只需把引脚定义改下即可。
freertos任务源码;
void Sgm41511_task(void *argument)
{
/* USER CODE BEGIN Sgm41511_task */
/* Infinite loop */
SGM41511_IIC_Init();
SGM41511_WriteReg00(0x17); // Write 0x17 to REG00 00010111
SGM41511_WriteReg07(0xDC) ;// Write 0xDC to REG07 11011100
SGM41511_WriteReg06(0x9E) ;// Write 0x9E to REG06 10011110
SGM41511_WriteReg05(0xB8) ;// Write 0xB8 to REG05 10111000
SGM41511_WriteReg04(0x5B) ;// Write 0x5B to REG04 01011011
SGM41511_WriteReg03(0x21) ;// Write 0x21 to REG03 00100001
SGM41511_WriteReg02(0xE2) ;// Write 0xE2 to REG02 11100010
SGM41511_WriteReg01(0x7E) ;// Write 0x7E to REG02 01111110
SGM41511_WriteReg0B(0x94) ;// Write 0x94 to REG0B 10010100
for(;;)
{
SGM41511_ReadAllRegisters();//5s循环读取SGM41511所有寄存器信息
osDelay(5000);
}
/* USER CODE END Sgm41511_task */
}
逻辑main.c简单调用
void main(void)
{
SGM41511_IIC_Init();
SGM41511_WriteReg00(0x17); // Write 0x17 to REG00 00010111
SGM41511_WriteReg07(0xDC) ;// Write 0xDC to REG07 11011100
SGM41511_WriteReg06(0x9E) ;// Write 0x9E to REG06 10011110
SGM41511_WriteReg05(0xB8) ;// Write 0xB8 to REG05 10111000
SGM41511_WriteReg04(0x5B) ;// Write 0x5B to REG04 01011011
SGM41511_WriteReg03(0x21) ;// Write 0x21 to REG03 00100001
SGM41511_WriteReg02(0xE2) ;// Write 0xE2 to REG02 11100010
SGM41511_WriteReg01(0x7E) ;// Write 0x7E to REG02 01111110
SGM41511_WriteReg0B(0x94) ;// Write 0x94 to REG0B 10010100
while(1)
{
SGM41511_ReadAllRegisters();//5s循环读取SGM41511所有寄存器信息
HAL_Delay(5000);
}
}
SGM41511 寄存器各个的深度含义请在我的发布文章里找;
完整例程代码请下载:
通过网盘分享的文件:charge_iic.rar
链接: https://pan.baidu.com/s/1M393qc0XidG8LWjDKJmqAQ?pwd=4syw 提取码: 4syw