如何使用STM32F1/F4驱动CS5463

如何使用STM32F1/F4驱动CS5463

一,前言

第一篇博客,记录一下我的毕设,写的不好的地方大家见谅。在我的毕设里,其中一个部分用到了一个电能测量的模块CS5463,在淘宝买到的附带程序基本都是51的程序,但是本人用的主控是STM32F4系列的核心版,具体型号是STM32F407ZG(和正点原子探索者是同一块芯片啦),这就面临着要把CS5463的51的驱动代码移植到32上面。

其实我在网上有找过很多别人改写的驱动代码,也花钱买了据说亲测有效的驱动,未果。不是写的很乱,不然就是一点数据都读不出来。刚开始用的时候是从买别人的32驱动中下手,从别人的代码里改错,但是就是一直读到寄存器的值都是0,后来一气之下决定还是一句一句从51那边改驱动过来。

改这个驱动代码,其实最主要要改的便是读写寄存器和芯片初始化的地方,只要芯片的SPI时序对了,SPI能正常通信,芯片初始化成功,便能成功读到各个寄存器的数据。

二、SPI时序,引脚

CS5463这个芯片和单片机通信最主要是通过SPI通信的,芯片还具有一个中断引脚(在51那边的程序里,中断引脚没用上,所以在改到32时,中断引脚依然没接),下面把贴一下该模块的引脚图。
需要接的引脚
在32里面,SPI通信可以使用32硬件的时序,也可以使用软件模拟SPI的时序,本文里驱动SPI是使用软件模拟的方式,我一共用了2块板子成功驱动了这个模块,一个是正点原子F1精英版(主控STM32F103ZE),另一个是正点原子F4探索者板子(主控STM32F407ZG),如果有这两块板子的朋友们可以直接下我的程序到板子上试试。

三、注意事项

有一个需要注意的地方!非常重要! 无论用F1还是F4,也应该说只要是用32,就一定要注意!因为STM32的IO端口是分为输入模式和输出模式的,在SPI通信之中,有DO引脚,这个引脚在端口配置是要设置为输入模式的,(因为使用51,端口配置是不分输入输出的,所以在32里面要极为注意端口配置)。

注意: 目前本人用的工程模板为正点原子的模板,然后库函数里,F1和F4的端口配置也有细微的区别 ,下面也详细介绍一下这个区别。

在F1里面,端口配置如下:
在这里插入图片描述
在F1里,除了DO端口(在图中为PF3)设置为上拉输入(GPIO_Mode_IPU)之外,其他端口设置为推挽输出 (GPIO_Mode_Out_PP),IO的速度统一设置为50Mhz。

在F4里面,端口配置如下:
在这里插入图片描述
在F4里,除了DO端口(在图中为PA3)先设置为普通输入模式(GPIO_Mode_IN),然后设置为上拉模式(GPIO_PuPd_UP)之外;其他端口先设置为普通输出模式(GPIO_Mode_OUT),再设置为推挽输出模式(GPIO_OType_PP),IO的速度统一设置为50Mhz。

从代码中大家可以看出F1和F4的细微区别,但其实原理都一样。

四、驱动代码

另外需要注意的是,因为大家使用的电流传感器(电感绕的线圈扎数一般情况都不一样,所以建议大家在电流或者电压比例那个做一个小小的计算),目前贴出来的这个比例是只适用我自己的,比如在测电流函数中的 result = 3.23 * result + 7.62;这一句代码,是我根据我读到的寄存器的值和我实际的电流值用matlab做了拟合而得到的,所以各位在使用各个测量的函数时(比如测电流、电压、功率等),大家都需要自行对这个值与真实值进行校准。

改此驱动难点在于芯片是否和单片机通信成功,只要通信成功,单片机可以从芯片中读到值了,只要这个模块不是坏的,之后的数据处理都是小问题,由于电流互感器(这个模块使用的是电感),电压互感器感应到的值和实际值基本呈线性的关系,所以即使不用matlab去拟合得这么精确的函数,自己手算也能算出一个大概值,只要通过从芯片寄存器读到的值与实际值计算一个比例关系即可。

下面直接贴代码。(在此展示F1的驱动代码,使用F4的同学按照上面的提示相应的改端口驱动就行)。

#include "CS_5463.h"
 u8 RX_Buff[4];					//CS5463读写缓冲区
#define CS5463_VScale       525             //计算电压比例,220V*250mv/110mv=500V
#define CS5463_IScale       500      //计算电流比例   (250/10) 
 #define RST_CS5463     GPIO_Pin_0
 #define CS_CS5463      GPIO_Pin_1
 #define INT_CS5463     GPIO_Pin_2
 #define DO_CS5463      GPIO_Pin_3
 #define DI_CS5463      GPIO_Pin_4
 #define SCK_CS5463     GPIO_Pin_5

 void CS5463_Io_Init(void )
{	
	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);	 //使能F端口时钟
	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_5;				
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
 GPIO_Init(GPIOF, &GPIO_InitStructure);			
	
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	
GPIO_Init(GPIOF, &GPIO_InitStructure);	
	
 GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);		
 }    

void CS5463_Init(void )
{	
	CS5463_Io_Init();  
	GPIO_WriteBit(GPIOF,RST_CS5463 , Bit_RESET);
	delay_us(100);
	GPIO_WriteBit(GPIOF, RST_CS5463, Bit_SET);
	
//发送同步序列
    RX_Buff[0] = CMD_SYNC1;
    RX_Buff[1] = CMD_SYNC1;
    RX_Buff[2] = CMD_SYNC0;
    CS5463WriteReg(CMD_SYNC1,RX_Buff);   //#define CMD_SYNC1       0XFF    //开始串口重新初始化
//----------------------
//初始化--配置寄存器
//相位补偿为PC[6:0]=[0000000];
//电流通道增益为Igain=10;
//EWA=0;
//INT中断为低电平有效IMODE:IINV=[00]
//iCPU=0
//K[3:0]=[0001]
    RX_Buff[0] = 0x00;
    RX_Buff[1] = 0x00;
    RX_Buff[2] = 0x01;
    CS5463WriteReg(REG_CONFR,RX_Buff);  // #define REG_CONFR       0x40    //配置
//----------------------
//初始化--操作寄存器
    RX_Buff[0] = 0x00; //B0000_0000;
    RX_Buff[1] = 0x00; //B0000_0000;
    RX_Buff[2] = 0x60; //B0110_0000;
    CS5463WriteReg(REG_MODER,RX_Buff);   //#define REG_MODER       0x64    //操作模式
//初始化--CYCLE COUNT 寄存器,4000
    RX_Buff[0] = 0x00;
    RX_Buff[1] = 0x0F;
    RX_Buff[2] = 0xA0;                     //#define REG_CYCCONT   0x4A    //一个计算周期的A/D转换数
    CS5463WriteReg(REG_CYCCONT,RX_Buff);   //初始化--CYCLE COUNT 寄存器,4000
//----------------------
    RX_Buff[0] = 0xFF;
    RX_Buff[1] = 0xFF;
    RX_Buff[2] = 0xFF;
    CS5463WriteReg(REG_STATUSR,RX_Buff);   //初始化--状态寄存器  #define REG_STATUSR   0x5E    //状态
//----------------------
    RX_Buff[0] = 0x80;                     //开电流、电压、功率测量完毕中断
    RX_Buff[1] = 0x00;
    RX_Buff[2] = 0x80;                     //开温度测量完毕中断
    CS5463WriteReg(REG_MASKR,RX_Buff);     //初始化--中断屏蔽寄存器    #define REG_MASKR       0x74    //中断屏蔽
//----------------------
    RX_Buff[0] = 0x00;
    RX_Buff[1] = 0x00;
    RX_Buff[2] = 0x00;
    CS5463WriteReg(REG_CTRLR,RX_Buff);     //初始化--控制寄存器   #define REG_CTRLR    0x78    //控制
//----------------------
   CS5463CMD(CMD_STARTC);                 //启动连续转换      #define CMD_STARTC      0XE8    //执行连续计算周期
                
}
void CS5463WriteReg(u8 addr,u8 *p)
{
 u8 i,j;
 u8 dat;

	GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_RESET);
 i = 0;
 while(i<8)
 {
    delay_us(50);
	 GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_RESET);
	 
	if(addr&0x80) GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
	else		GPIO_WriteBit(GPIOF,DI_CS5463, Bit_RESET);
	    delay_us(50);

   GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);	 			//在时钟上升沿,数据被写入CS5463
	addr <<= 1;
	i++;
 }
 j = 0;
 delay_us(50);
 while(j<3)
 {
  	dat = *(p+j);
	i = 0;
	while(i<8)
	{
  		 delay_us(50);
	 GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_RESET);
		
		if(dat&0x80) GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
		else		GPIO_WriteBit(GPIOF,DI_CS5463, Bit_RESET);
	 delay_us(50);
		
			GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);	  		//在时钟上升沿,数据被写入CS5463
		dat <<= 1;
		i++;
	}
	 delay_us(50);
	j++;
 }
   GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
	GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_SET);
   delay_us(50);
}
void CS5463CMD(u8 cmd)
{
 u8 i;
GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);	
	GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_RESET);
	i=0;
 while(i<8)
 {
   delay_us(50);
GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_RESET);	
if(cmd&0x80) GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
		else		GPIO_WriteBit(GPIOF,DI_CS5463, Bit_RESET);
	delay_us(50);
 GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);			 		//在时钟上升沿,数据被写入CS5463
	cmd <<= 1;
	i++;
 }
 delay_us(50);
 GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
 GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_SET);
}
void CS5463ReadReg(u8 addr,u8 *p)
{
	 
 u8 i,j;
 u8 dat;
 GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_RESET);
 addr &= READ_MASK;
 i = 0;
 while(i<8)
 {
  	delay_us(50);
	GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_RESET);
	 
	if(addr&0x80) GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
	 
	else		GPIO_WriteBit(GPIOF,DI_CS5463, Bit_RESET);
	 
	delay_us(50);
	 
	GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);	
	addr <<= 1;				 	//在时钟上升沿,数据被写入CS5463
	i++;
 }
 j = 0;
	GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
 
 while(j<3)
 {
	i = 0;
	dat = 0;
	while(i<8)
	{
		delay_us(50);
		GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_RESET);	
		if(i==7)GPIO_WriteBit(GPIOF,DI_CS5463, Bit_RESET);
		
		else	 GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
		
	
		delay_us(50);
		dat <<= 1;			 
		if(GPIO_ReadInputDataBit(GPIOF,DO_CS5463 ))  dat |= 0x01;
		else	dat &= 0xFE;
	GPIO_WriteBit(GPIOF,SCK_CS5463, Bit_SET);	
		delay_us(50);			 		
		i++;
	}
	*(p+j) = dat;
	j++;
 }
delay_us(50);	
GPIO_WriteBit(GPIOF,DI_CS5463, Bit_SET);
GPIO_WriteBit(GPIOF,CS_CS5463  , Bit_SET);
}

/**6***********************************************************
** 函数名称:CS5463_ResetStatusReg
** 函数功能:复位状态寄存器函数
** 函数参数:无
** 第一次修改时间:无
**************************************************************/
void CS5463_ResetStatusReg(void)
{
 RX_Buff[0] = 0xFF;
 RX_Buff[1] = 0xFF;
 RX_Buff[2] = 0xFF;
 CS5463WriteReg(0x5E,RX_Buff);		//复位状态寄存器	#define REG_STATUSR 	0x5E 	//状态  
}


u8 CS5463_GetStatusReg(void )
{ 
 u8 sta1=0;
 CS5463ReadReg(0x1E,RX_Buff);	   //1E 是什么?   状态寄存器
		  
 if(RX_Buff[0]&0x80)		   			//检测:电流、电压、功率测量是否完毕
 {
	//检测电流/电压是否超出范围
	//检测电流有效值/电压有效值/电能是否超出范围
	if((RX_Buff[0]&0x03)||(RX_Buff[1]&0x70))
	{
	 	CS5463_ResetStatusReg();		//复位状态寄存器

	}
	else
	{
		sta1 |= 0x01;//B0000_0001;	//这什么意思 还可以这样写吗? PT2017-2-8   分隔符吗? 
	}
 }

 if(RX_Buff[2]&0x80)			   	//检测:温度测量是否完毕
 {
  	sta1 |=0x02; //B0000_0010;
 }  
 
 return(sta1);	
}  

u32 CS5463_GetCurrentRMS()
{
 float  G = 0.5,result;
 u32 temp1;
 u8 temp,i,j;
	
CS5463ReadReg(REG_IRMSR,RX_Buff);   		//读取电流有效值
 //SndCom1Data(RX_Buff,3);
 i = 0;
 result = 0;
 while(i<3)
 {
  	temp = RX_Buff[i];			   		
	j = 0;
	while(j<8)
	{
	 	if(temp&0x80)
		{
		 	result += G;	
		}
		temp <<= 1;
		j++;
		G = G/2;	
	}
	i++;
 }
 result = result*CS5463_IScale;//I_Coff;						//计算电流值 暂时不用 
 result *= 1000;								//单位mA(毫安)  12345ma
 result = 3.23 * result + 7.62;
 temp1 = (u32)result;
return temp1; 
 }
u32 CS5463_GetPactiveRMS(void )
{
 float G = 1.0,result;
 u8 temp,i,j;
 u32 temp1;
 CS5463ReadReg(0x14,RX_Buff);   	//读取有功功率REG_Pactive
 //SndCom1Data(RX_Buff,3);
 temp = RX_Buff[0];
 if(temp&0x80)						  	//如果为负数,计算原码
 { 	
 }
 i = 0;
 result = 0;
 while(i<3)
 {
  	temp = RX_Buff[i];			   		
	j = 0;
	while(j<8)
	{
	 	if(temp&0x80)
		{
		 	result += G;	
		}
		temp <<= 1;
		j++;
		G = G/2;	
	}
	i++;
 }
// result = result*P_Coff;				//计算功率,单位W(瓦特)
// result = Vrms*Irms;					直接计算功率
  result = result*13125;
 temp1 = (u32)result; 
 return temp1;
 }

u32 CS5463_GetPowerFactor(void)
{
 float  G = 1.0,result;
 u8 temp,i,j;
 u32 temp1;
 CS5463ReadReg(0x32,RX_Buff);   		//读取功率因数
 //SndCom1Data(RX_Buff,3);
 temp = RX_Buff[0];
 if(temp&0x80)						  	//如果为负数,计算原码
 {
  	RX_Buff[0] = ~RX_Buff[0];			//本来为取反+1,这里因为精度的原因,不+1
	RX_Buff[1] = ~RX_Buff[1];
	RX_Buff[2] = ~RX_Buff[2];		 	
 }
 i = 0;
 result = 0;
 while(i<3)
 {
  	temp = RX_Buff[i];			   		
	j = 0;
	while(j<8)
	{
	 	if(temp&0x80)
		{
		 	result += G;	
		}
		temp <<= 1;
		j++;
		G = G/2;	
	}
	i++;
 }
 result *= 10000;
 temp1 = (u32)result;
 return  temp1;
 }
u32 CS5463_GetTemperature(void)	  //温度能显示了 PT2017-2-12
{
 float G = 128,result;
 u8 temp,i,j;
 u32 temp1;
 CS5463ReadReg(0x26,RX_Buff);   		//读取温度	是的在这里就读到了温度 
 //SndCom1Data(RX_Buff,3);
 temp = RX_Buff[0];
 if(temp&0x80)						  	//如果为负数,计算原码
 {
 							//负数标志
	RX_Buff[0] = ~RX_Buff[0];			//本来为取反+1,这里因为精度的原因,不+1
	RX_Buff[1] = ~RX_Buff[1];
	RX_Buff[2] = ~RX_Buff[2];		 	
 }
 i = 0;
 result = 0;    //这个值是浮点数 先清零 再逐个把0.5的权 数据加进来
 while(i<3)
 {
  	temp = RX_Buff[i];	//虽然这个数组定义了4个字节 实际就用了 Buff[0]  Buff[1]  RX_Buff[2]		   		
	j = 0;
	while(j<8)
	{
	 	if(temp&0x80)
		{
		 	result += G;	//把0.5的权数据加进来		  
		}
		temp <<= 1;
		j++;
		G = G/2;	
	}
	i++;
 }
 if(result<128)			  //是的这个result 是 -127,128   这里已经获取了温度浮点值 最多是一个3位数? 还有小数点 
 {
 	result *= 100;
	temp1 = (u32)result;	  //是的 这里就是 例如12523  -----> 125.23  怎么去显示? 如何分离 从8A开始显示	 
 }
 	return temp1;
  }

  • 31
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
### 回答1: stm32f103c8是一款32位的ARM Cortex-M3微控制器,而CS5463是一款电能计量芯片。要驱动CS5463,我们需要首先连接CS5463stm32f103c8。 一般情况下,需要使用SPI(串行外设接口)进行通信。首先,我们需要配置stm32f103c8的SPI模块。设置SPI的工作模式、数据位大小、主从模式、CPOL和CPHA等参数。然后,配置GPIO口作为SPI的片选(CS)信号,用于选中CS5463。 接下来,我们可以开始编写驱动程序。首先,我们需要编写代码来初始化SPI和GPIO口。使用SPI发送命令和读取数据的函数来与CS5463进行通信。根据CS5463的规格书,可以编写相应的函数来读取和写入寄存器,配置寄存器以控制CS5463的行为。 在驱动程序中,我们可以使用中断来处理读取数据的过程,以及相关的错误处理。还可以编写一些函数来解析和处理CS5463返回的数据。 需要注意的是,编写驱动程序需要参考CS5463芯片的数据手册和相关资料,了解其通信协议和寄存器的使用方法。此外,还需要检查stm32f103c8的技术手册,了解其SPI模块的具体功能和寄存器的使用方法。 最后,编译和烧录驱动程序到stm32f103c8上,连接CS5463,并测试驱动程序的功能。通过读取CS5463返回的数据,可以验证驱动程序是否正常工作,并可以根据需要进行进一步的调试和优化。 以上是关于如何驱动CS5463的简要介绍,希望对您有所帮助。 ### 回答2: STM32F103C8驱动CS5463需要连接CS5463的引脚和STM32F103C8的引脚,并编写相应的代码来配置和控制CS5463。 首先,需要用引脚连接STM32F103C8和CS5463CS5463的供电引脚 VDD 和 GND 需要连接到STM32F103C8的相应的电源引脚,以确保CS5463获得正确的电源。另外,CS5463的其他引脚,如SPI总线的SCK引脚、MISO引脚、MOSI引脚,以及片选引脚,需要连接到STM32F103C8的相应的引脚。 接下来,需要在STM32F103C8的代码中配置和控制CS5463。首先,需要定义和初始化SPI总线的控制器,以便与CS5463进行通信。然后,可以通过SPI总线发送和接收命令和数据来控制和读取CS5463的状态和数据。在驱动CS5463时,可能需要编写一些函数来封装SPI总线的读写操作,以方便后续的调用和使用。 例如,可以编写一个函数来配置CS5463的参数,如采样率、滤波器设置和校准等。这个函数可以通过SPI总线向CS5463发送相应的命令和数据,来配置CS5463的内部寄存器。 另外,还可以编写其他函数来读取CS5463的测量结果,如电压、电流和功率等。这些函数也可以使用SPI总线来与CS5463进行通信,并返回正确的测量结果。 需要注意的是,具体的代码实现会根据具体的应用和要求有所变化。因此,在实际驱动CS5463时,需要参考STM32F103C8的开发文档和CS5463的数据手册,并根据具体的硬件连接和功能需求,进行相应的代码编写和调试,以确保CS5463能够正常工作并获取准确的测量结果。 ### 回答3: 驱动CS5463芯片需要与STM32F103C8微控制器进行通信。首先,需要初始化STM32SPI通信接口,配置SPI端口的模式、时钟频率和数据位等参数。然后,通过SPI接口向CS5463芯片发送控制和配置命令,例如设置测量通道和增益,选择参考电压源和输入电流范围等。通过读取和写入SPI数据寄存器,可以发送和接收数据。 为了读取CS5463芯片的测量结果,需要向其发送特定的读取命令,并等待芯片返回数据。读取的数据可以通过STM32SPI数据寄存器获取,并进行解析和处理。可以使用适当的位操作和移位运算来提取和转换芯片返回的原始数据,例如电压、电流和功率等。 除了SPI接口,还需要正确连接STM32CS5463芯片的引脚,包括时钟引脚(SCK)、数据输入引脚(MOSI)、数据输出引脚(MISO)和片选引脚(CS)。在配置STM32引脚功能时,需要将其设置为SPI模式,以实现正确的通信。 最后,为了实现稳定和精确的测量,可能需要对CS5463芯片进行校准和校验。校准可以通过发送和接收校准命令来完成,使用已知准确值的参考电压和电流进行比较和调整,以提高测量的准确性。 总之,驱动CS5463芯片需要正确配置STM32SPI通信接口,并通过发送和接收SPI数据来控制和读取芯片的测量数据。这需要适当的引脚连接、命令发送和数据处理等步骤,以确保稳定和精确的测量结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值