中颖SH367309

本文详细介绍了SH367309芯片,一款专为锂电池Pack设计的数字前端芯片,具备多种工作模式,如保护模式、采集模式、仓运模式和烧写模式,以及其关键管脚功能和保护特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、SH367309芯片介绍

注意:配置AFE的EEPROM寄存器时只能写入一次,写入前读取00-19H的数据,如果写入的内容和读取的内容相同,则不写入

二、SH367309的四种工作模式

(1)保护模式

        MODE管脚外接低电平V L-MODE ,SH367309工作在保护模式,SH367309开启内置保护功能模块,开启平衡功能,关闭看门狗和TWI通讯模块。

(2)采集模式

        MODE管脚外接高电平V H-MODE ,SH367309工作在采集模式。开启内置保护功能模块,开启TWI通讯模块,MCU可通过TWI通讯模块操作SH367309内部寄存器。

(3)仓运模式

        SHIP管脚外接低电平V L-SHIP ,SH367309进入仓运模式。关闭充放电MOSFET,同时关闭所有功能模块。

(4)烧写模式

        VPRO管脚外接EEPROM烧写电压V PRO ,且延时10mS,SH367309进入烧写模式。关闭充放电MOSFET及内置保护功能模块。此时其他设备可通过TWI接口读/写内置EEPROM,且内置EEPROM仅在烧写模式下方可进行写操作。

注意:

1、ROM中数据不需要等待ALARM管脚信号采集到数据后在读取

2、改写AFE的ROM数据后,需要复位才能生效

SH367309_SHIP_Lo;      
delay_1ms(100); 
SH367309_SHIP_Hi;	
delay_1ms(100);	

3、SH367309默认关闭CADC电流采集,如果需要电流采集的功能,主动配置0x40寄存器

4、退出仓运模式或者进入烧写模式时,需要延时10ms以上等待电路稳定

SH367309_SHIP_Hi;       //使能AFE的SHIP引脚,AFE退出休眠
delay_1ms(100);         //延迟100mS


SH367309_VPRO_Hi;	     //使能AFE的VPRO烧写功能(可以对EEPROM进行配置)
delay_1ms(100);        //延时,等待电平稳定


 

三、ALARM管脚

ALARM 管脚:SH367309处于采集模式下,ALARM管脚为对外通讯管脚;处于保护模式下,ALARM管脚为高阻态。采集模式下,ALARM管脚正常输出逻辑高电平。出现下表中的系统状态,ALARM管脚输出一个低电平脉冲。出现下表中的系统状态,ALARM管脚输出一个低电平脉冲。

将ALARM引脚配置为外部中断,下降沿触发,即每触发一次中断,说明数据已经采集完成一次。

void Afe_Init(void)
{
        gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_0);	   //ALARM检测口配置为外部中断
		nvic_irq_enable(EXTI0_IRQn, 2U, 0U);                               //使能外部中断0线程 
		gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOA, GPIO_PIN_SOURCE_0);//配置外部中断对应端口
		exti_init(EXTI_0, EXTI_INTERRUPT, EXTI_TRIG_FALLING);              //外部中断0,下降沿触发 
		exti_interrupt_flag_clear(EXTI_0);                                 //清外部中断0标志
}


void EXTI0_IRQHandler(void)
{
	if(RESET != exti_interrupt_flag_get(EXTI_0))
	{
			exti_interrupt_flag_clear(EXTI_0);
			tagSBS.bAlarm = ISYES; //ALARM置1		
	}
}

void ReadAFEData()  
{
		static unsigned char afecomcount1,afecomcount2;
		if(tagSBS.bAlarm == ISYES)
		{
				tagSBS.bAlarm = ISNO;	
			    TwiRead(0x34,0X00,26,tagBMS.ucReadAFERegister);
                TwiRead(0x34,0X40,51,tagBMS.ucReadAFERegister+0X40)) 
		}
}

void task4(void *pvParameters)
{
    while(1)
    {	
                vTaskDelay(1000);        //1S	
				ReadAFEData();//读AFE寄存器
    }	
}

四、工作流程

1、退出仓运模式

2、初始化AFE ROM参数,读AFE ROM 00-19H数据,判断初始化参数和读取参数是否一致,不一致写入数据

3、配置0x40寄存器,使能CADC进行电流采集,判断ALARM引脚是否采集数据完毕,完毕后读AFE RAM数据

五、通信协议代码

TWI通讯中,SH367309作为从机,其固定地址是 0x34( | )最低位0写1读

 twi.c

#include "twi.h"   
unsigned char const CRC8Table[]=
{							//120424-1			CRC Table
	0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15,0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D,
	0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65,0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D,
	0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5,0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD,
	0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85,0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD,
	0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2,0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA,
	0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2,0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A,
	0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32,0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A,
	0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42,0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A,
	0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C,0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4,
	0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC,0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4,
	0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C,0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44,
	0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C,0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34,
	0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B,0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63,
	0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B,0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13,
	0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB,0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83,
	0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB,0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3
};

void Delay4us(void) //4uS
{
	uint32_t ticks;
	uint32_t told,tnow,reload,tcnt=0;

	reload = SysTick->LOAD;                     //获取重装载寄存器值
	ticks = 4 * (SystemCoreClock / 1000000);    //计数时间值   括号里的代表1us秒嘀嗒定时器的value会向下降多少值
	told=SysTick->VAL;                          //获取当前数值寄存器值(开始时数值)
	while(1)
	{
		tnow=SysTick->VAL;          //获取当前数值寄存器值
		if(tnow!=told)              //当前值不等于开始值说明已在计数
		{         
			if(tnow<told)             //当前值小于开始数值,说明未计到0
			tcnt+=told-tnow;     //计数值=开始值-当前值 
			else                      //当前值大于开始数值,说明已计到0并重新计数
			tcnt+=reload-tnow+told;   //计数值=重装载值-当前值+开始值  (已从开始值计到0) 
			told=tnow;                //更新开始值
			if(tcnt>=ticks)break;     //时间超过/等于要延迟的时间,则退出.
		} 
	} 
}

void TWI_Init(void)
{
    rcu_periph_clock_enable(RCU_GPIOB);
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
	TWI_DAT_HIGH;
	TWI_CLK_HIGH;	
}

void TwiStart(void)
{
	TWI_DAT_HIGH;
	TWI_CLK_HIGH;
	TWI_DAT_OUT;
	TWI_CLK_OUT;
	TWI_DAT_LOW;
	Delay4us();
	TWI_CLK_LOW;
}

void TwiReStart(void)
{
	TWI_DAT_HIGH;
	TWI_CLK_HIGH;
	Delay4us();
	TWI_DAT_LOW;
	Delay4us();
	TWI_CLK_LOW;
}

void TwiStop(void)
{
	TWI_DAT_OUT;
	TWI_DAT_LOW;
	Delay4us();
	TWI_CLK_HIGH;
	Delay4us();
	TWI_DAT_HIGH;
	Delay4us();
	TWI_DAT_IN;
	TWI_CLK_IN;
}

//SH367309接收好数据后,释放SCL信号线,所以此函数可以判断通信是否成功
unsigned char TwiChkClkRelease(void)
{
	unsigned int TimeoutCnt=1000;				//If Clock is not released within 4ms, is considered overtime
	unsigned char result=0;
	TWI_CLK_IN;
	while(TimeoutCnt--)
	{
		Delay4us();
		if(TWI_RD_CLK)
		{
			result = 1;
			break;
		}
	}
	TWI_CLK_HIGH;
	TWI_CLK_OUT;
	return result;
}

unsigned char TwiSendData(unsigned char Data, unsigned char ClkFlg)
{
	unsigned char i;
	unsigned char result=0;
//1. After sending the Start signal, there is no need to detect Clock is released, And sending the first bit
	if(Data&0x80)
	{
		TWI_DAT_HIGH;
	}
	else
	{
		TWI_DAT_LOW;
	}
	if(ClkFlg == 1)
	{
		Delay4us();
		if(TwiChkClkRelease())
		{
			TWI_CLK_LOW;
		}
		else
		{
			return result;//返回0表示通信失败
		}
	}
	else
	{
		Delay4us();
		TWI_CLK_HIGH;
		Delay4us();
		TWI_CLK_LOW;
	}
	
//2. Send the remaining seven bit
	Data = Data<<1;
	for(i=0; i<7; i++)
	{
		if(Data&0x80)
		{
			TWI_DAT_HIGH;
		}
		else
		{
			TWI_DAT_LOW;
		}
		Data = Data<<1;
		Delay4us();
		TWI_CLK_HIGH;
		Delay4us();
		TWI_CLK_LOW;
	}
	TWI_DAT_IN;
	Delay4us();
	
	for(i=0; i<10; i++)
	{
		if(TWI_RD_DAT == 0)
		{
			result = 1;
			break;
		}
	}
	TWI_CLK_HIGH;

	Delay4us();
	TWI_DAT_LOW;
	TWI_DAT_OUT;
	TWI_CLK_LOW;
	Delay4us();
	
	return result;//返回1有应答,返回0无应答
}

unsigned char TwiGetData(unsigned char AckFlg)
{
	unsigned char i, RdData=0;
	
	TWI_DAT_IN;
	Delay4us();
	for(i=0; i<8; i++)
	{
		TWI_CLK_HIGH;
		Delay4us();
		if(TWI_RD_DAT)
		{
			RdData |= (1<<(7-i));
		}
		TWI_CLK_LOW;
		Delay4us();
	}

	TWI_DAT_OUT;
	if(AckFlg != 0)
	{
		TWI_DAT_LOW;
	}
	else
	{
		TWI_DAT_HIGH;
	}
	TWI_CLK_HIGH;
	Delay4us();
	TWI_CLK_LOW;
	Delay4us();
	
	return RdData;
}

unsigned char CRC8cal(unsigned char *p, unsigned char Length)    		   //look-up table calculte CRC 
{    
    unsigned char crc8 = 0;    
    
	for(; Length > 0; Length--)
	{    
        crc8 = CRC8Table[crc8^*p];    
	    p++;    
    } 
       
    return(crc8);       
}


unsigned char TwiWrite(unsigned char SlaveID, unsigned int WrAddr, unsigned char Length, unsigned char *WrBuf)
{
	unsigned char i;
	unsigned char TempBuf[4];
	unsigned char result = 0;
	TempBuf[0] = SlaveID;
	TempBuf[1] = (unsigned char)WrAddr;
	TempBuf[2] = *WrBuf;
	TempBuf[3] = CRC8cal(TempBuf, 3);
	
	if(Length > 0)
	{
		TwiStart();
		if(!TwiSendData(SlaveID, 1))			//Send Slave ID
		{
				goto WrErr;
		}
		if(TwiSendData(WrAddr, 0))					//Send Write Address(Low 8bit)
		{
			result = 1;
			for(i=0; i<Length; i++)
			{
				if(TwiSendData(*WrBuf, 0))			//Send Write Data
				{
					WrBuf++;
				}
				else
				{
					result = 0;
					break;
				}
			}
			if(!TwiSendData(TempBuf[3], 0))            //write CRC
			{
					result = 0;
			}
		}
		WrErr:
		TwiStop();
	}
	return result;
}
unsigned char TwiRead(unsigned char SlaveID, unsigned int RdAddr, unsigned char Length, unsigned char *RdBuf)
{
	unsigned char i;
	unsigned char result=0;
	unsigned char TempBuf[46];
	unsigned char RdCrc=0;

	TempBuf[0] = SlaveID;
	TempBuf[1] = (unsigned char)RdAddr;
	TempBuf[2] = Length;
	TempBuf[3] = SlaveID | 0x01;

	if(Length > 0)
	{
		TwiStart();								//开始
		if(!TwiSendData(SlaveID, 1))			//Send Slave ID
		{
			goto RdErr;
		}	
		if(!TwiSendData(RdAddr, 0))				//Send Read Address(Low 8bit)
		{
			goto RdErr;
		}
		if(!TwiSendData(Length, 0))
		{
				goto RdErr;
		}
		TwiReStart();	
		if(TwiSendData(SlaveID|0x1, 0))			//Send Slave ID
		{
			result = 1;

			for(i=0; i<Length+1; i++)
			{
				if(i == Length)
				{
					RdCrc = TwiGetData(0);      //Get Data
				}
				else
				{
					TempBuf[4+i] = TwiGetData(1);     //Get Data
				}
			}
			if(RdCrc != CRC8cal(TempBuf, 4+Length))
			{
				result = 0;    
			}
			else
			{
				for(i=0; i<Length; i++)
				{
					*RdBuf = TempBuf[4+i];
					RdBuf++;   
				}
			}
		}

		RdErr:
		TwiStop();
	}

	return result;
}


/*特别注意,写eeprom必须要使能烧写模式,其他的读eeprom,ram或者写ram正常即可
void WriteAFEData_EEPROM()
{
		TwiRead(0x34,0X00,26,tagBMS.ucReadAFERegister);	//读AFE的EEPROM寄存器,地址(00H-19H 即 0-25),共26个8位寄存器
		if(memcmp(tagBMS.ucWriteAFERegister,tagBMS.ucReadAFERegister,25)!=0) //存储区str1、str2前n个字节比较,0=无区别,!=0有区别	
		{
				UCHAR i;
				SH367309_VPRO_Hi;	     //使能AFE的VPRO烧写功能(可以对EEPROM进行配置)
				delay_1ms(100);        //延时,等待电平稳定
				for(i=0; i<25; i++) 	 //写AFE的EEPROM寄存器,地址(00H-19H 即 0-25),共26个8位寄存器
				{
						delay_1ms(5);
						if(!TwiWrite(0x34, i, 1, tagBMS.ucWriteAFERegister+i))
						{
								tagSBS.bAFEFaultStatus = ISYES;//写AFEROM出现错误						
						}
				} 
				SH367309_VPRO_Lo;	 //关闭AFE的VPRO烧写,进入正常读AFE模式	

				改写AFEROM参数后,需要复位后才能生效
				SH367309_SHIP_Lo;      
				delay_1ms(100); 
				SH367309_SHIP_Hi;	
				delay_1ms(100);			
		}
}*/

twi.h

#ifndef _TWI_H_
#define _TWI_H_
#include "head.h"

#define TWI_CLK_HIGH   gpio_bit_set(GPIOB, GPIO_PIN_8) 
#define TWI_CLK_LOW    gpio_bit_reset(GPIOB, GPIO_PIN_8)
#define TWI_DAT_HIGH   gpio_bit_set(GPIOB, GPIO_PIN_9) 
#define TWI_DAT_LOW    gpio_bit_reset(GPIOB, GPIO_PIN_9)
#define TWI_CLK_OUT    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8) //时钟口设置为输出
#define TWI_DAT_OUT    gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9) //数据口设置为输出
#define TWI_CLK_IN     gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8)    //时钟口设置为输入
#define TWI_DAT_IN     gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_9)    //数据口设置为输入
#define TWI_RD_CLK		 gpio_input_bit_get(GPIOB,GPIO_PIN_8)
#define TWI_RD_DAT		 gpio_input_bit_get(GPIOB,GPIO_PIN_9)

void TWI_Init(void);
void Delay4us(void); //4uS
void TwiStart(void);
void TwiReStart(void);
void TwiStop(void);
unsigned char TwiChkClkRelease(void);
unsigned char TwiSendData(unsigned char Data, unsigned char ClkFlg);
unsigned char TwiGetData(unsigned char AckFlg);
unsigned char CRC8cal(unsigned char *p, unsigned char Length);    		   //look-up table calculte CRC 
unsigned char TwiWrite(unsigned char SlaveID, unsigned int WrAddr, unsigned char Length, unsigned char *WrBuf);
unsigned char TwiRead(unsigned char SlaveID, unsigned int RdAddr, unsigned char Length, unsigned char *RdBuf);
void InitTwi(void);

#endif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值