TIC12400-Q1多路检测输入开关C语言底层驱动
前言
这个芯片用在汽车上,可能国内用的比较少,所以国内基本上除了能找到一本英文说明书以外,找不到其他什么资料了,更别说有什么驱动代码可以参考。在工作中,出于项目需要,不得不用到了这个芯片。我分享一下我自己调试的底层驱动和注意事项,供大家参考。
这个芯片有24路,可以用来检测每一路的通断状态(也可以说是高低电平),也可以用来测试ADC,我这里实际的项目是用来检测保险丝的通断状态。MCU检测个高低电平是再平常不过的事,但是这样一个芯片就可以检测24路,检测结果通过SPI通讯到MCU,所以极大减少了MCU的引脚需求,这点还是比较吸引人的。
说明书概览
芯片的引脚还是比较常规的,片选CS,SPI三根线SCLK,SI,SO,复位RESET(复位引脚记得按要求加上一个下拉电阻),INT标志位引脚,IN0~IN23输入引脚。
Vs供电电压可以最大40V,IN0~IN23最大输入电压也可以到40V,一般弱电控制,这个电压范围还是能满足绝大多数需求的。
我用的是STM32的芯片,STM32只支持8bit和16bit的SPI通讯,这个芯片是32bit的数据通讯,所以不能用STM32现成的SPI控制器,只能自己通过GPIO模拟SPI。时序图也是比较常规的SPI通讯,要注意的是,数据是在SCLK的下降沿进行数据交换,所以在下降沿之前SI引脚电平就要先选好,每个脉宽Tckh和Tckl都是120ns,也就是时钟高低电平的持续时间不能少许120ns。
这个芯片的复位方式有三种:上电复位,硬件复位,和软件复位(硬件和软件请自行查阅说明书),芯片每一次上电都会复位一次,所有的寄存器全部回到默认值。所以这个芯片的寄存器是没有记忆功能的,每次上电的时候都要对他的寄存器进行配置。
这是SPI通讯数据的读写数据格式。
如果要读取:
主站芯片发送的数据bit31需为0,bit25~bit30是要读取的寄存器地址。
主站芯片接收的数据bit25~bit30是芯片的一些状态标志位,具体可以对着说明书了解一下,我是直接忽略,bit1·-bit24是从寄存器里面获取出来的值。注意一点,寄存器的有效数据是从bit1开始的,不是从bit0开始的,bit0是校验位,这个把我害惨了。
如果是写入:
主站芯片发送的数据bit31需为1,bit25~bit30是要写入的寄存器地址,bit1-bit24是要写入的数据
主站芯片接收的数据bit25~bit30是芯片的一些状态标志位,bit1-bit24是对这个寄存器数据写入之前,寄存器的数据。
这个是全部寄存器的一个简介,因为我们是比较模式,只是比较高低电平,所以配置的寄存器比较少,只对那些有用的寄存器进行介绍一下
这个是芯片ID,没啥用,但是我是用来测试SPI的通讯是否正常,可以读取一下这个寄存器,看读出来的数据是否在bit4-bit10是0x2
这个寄存器比较重要,是个只读寄存器,24路的检测结果,是存储在这个寄存器的。从字面意思也很好理解,0是指输入的电压低于标定的阈值,1是指输入的电压高于标定的阈值。
这个寄存器是选项配置寄存器,很多使能位。我用的只是比较模式,所以很多位都默认就可以了。这里特别需要注意一下bit11,这个位是这个芯片的总开关,需要设1使能,芯片才能开始工作
这个是每一路通道的使能开关,自己根据需求打开,默认是全部关闭的。
这个是高低电平的判断阈值。默认情况下是,低于2V就是对GND连接,高于2V就是高电平连接。有2V,2.7V,3V,4V。根据自己需求来,我是默认2V
这是每个引脚的模式选择,默认是比较模式,也可以配置ADC模式(我没试过)
如果是用于判断高低电平的话,配置以上寄存器就足够了。
SPI读写代码:
u32 TIC12400Q1_Write(u8 addr, u32 data)
{
u8 bit;
u32 SentData = 0x80000000 , ReadData = 0; //写数据,bit31必须是1
SentData |= (addr << 25);
SentData |= ((data & 0xFFFFFF) << 1); //写入的有效数据从bit1开始
SCLK_L;
CSA_H;
delay_us(1);
CSA_L;
delay_us(1);
SCLK_H;
for(bit = 0 ; bit <32 ; bit++)
{
SCLK_H;
if((SentData & 0x80000000) == 0x80000000) SI_H;
else SI_L; //72M的时钟频率,我从示波器上测量出的高低电平持续
SCLK_L; //时间大于120ns,所以这里就不需要做任何延时了
SentData <<= 1;
if(SO) ReadData |= (0x80000000 >> bit);
}
SCLK_L;
delay_us(1);
CSA_H;
return (ReadData & 0x1FFFFFE) >>1; //移除掉所有的标志位和校验位,只返回寄存器的有效数据
}
u32 TIC12400Q1_Read(u8 addr)
{
u8 bit;
u32 SentData = 0x00000000 , ReadData = 0; //写数据,bit31必须是0
SentData |= (addr << 25);
SCLK_L;
CSA_H;
delay_us(1);
CSA_L;
delay_us(1);
SCLK_H;
for(bit = 0 ; bit <32 ; bit++)
{
SCLK_H;
if((SentData & 0x80000000) == 0x80000000) SI_H;
else SI_L;
SCLK_L;
SentData <<= 1;
if(SO) ReadData |= (0x80000000 >> bit);
}
SCLK_L;
delay_us(1);
;
CSA_H;
return (ReadData & 0x1FFFFFE) >>1; //移除掉所有的标志位和校验位,只返回寄存器的有效数据
}
void TIC12400Q1_1_32bitSPI_Init()
{
TIC12400Q1_Write(1,0x32,0); //全部设为比较模式
TIC12400Q1_Write(1,0x21,0x00); //比较阈值全部位2V
TIC12400Q1_Write(1,0x1C,0); //全部设为对GND
TIC12400Q1_Write(1,0x1B,0xFFFFFF); //所有通道全部使能
TIC12400Q1_Write(1,0x1A,0x800); //开始转换
}
以上全部是我的实际项目中的实际经验,代码也是实际验证过的。代码也有很多可以优化的地方。或许存在些许错误,如果哪位大神有发现错误的地方,请及时指正。
——冷亦花烟_CYB(菜蔡)
2019.3.7 23:51