如何使用STM32F1/F4驱动CS5463
一,前言 【stm32|如何使用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_VScale525//计算电压比例,220V*250mv/110mv=500V
#define CS5463_IScale500//计算电流比例(250/10)
#define RST_CS5463GPIO_Pin_0
#define CS_CS5463GPIO_Pin_1
#define INT_CS5463GPIO_Pin_2
#define DO_CS5463GPIO_Pin_3
#define DI_CS5463GPIO_Pin_4
#define SCK_CS5463GPIO_Pin_5 void CS5463_Io_Init(void )
{
GPIO_InitTypeDefGPIO_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_SYNC10XFF//开始串口重新初始化
//----------------------
//初始化--配置寄存器
//相位补偿为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_CONFR0x40//配置
//----------------------
//初始化--操作寄存器
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_MODER0x64//操作模式
//初始化--CYCLE COUNT 寄存器,4000
RX_Buff[0] = 0x00;
RX_Buff[1] = 0x0F;
RX_Buff[2] = 0xA0;
//#define REG_CYCCONT0x4A//一个计算周期的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_STATUSR0x5E//状态
//----------------------
RX_Buff[0] = 0x80;
//开电流、电压、功率测量完毕中断
RX_Buff[1] = 0x00;
RX_Buff[2] = 0x80;
//开温度测量完毕中断
CS5463WriteReg(REG_MASKR,RX_Buff);
//初始化--中断屏蔽寄存器#define REG_MASKR0x74//中断屏蔽
//----------------------
RX_Buff[0] = 0x00;
RX_Buff[1] = 0x00;
RX_Buff[2] = 0x00;
CS5463WriteReg(REG_CTRLR,RX_Buff);
//初始化--控制寄存器#define REG_CTRLR0x78//控制
//----------------------
CS5463CMD(CMD_STARTC);
//启动连续转换#define CMD_STARTC0XE8//执行连续计算周期}
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);
elseGPIO_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);
elseGPIO_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);
elseGPIO_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);
elseGPIO_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);
elseGPIO_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_STATUSR0x5E//状态
}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()
{
floatG = 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)
{
floatG = 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;
returntemp1;
}
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;
}
推荐阅读
- MCU项目技术总结|基于stm32F4的项目总结(控制层设计(四)直流有刷电机驱动原理及驱动器选型)
- 单片机毕业设计|800多套单片机毕业设计
- 嵌入式|网上五花八门的单片机教程,到底应该怎么整理学习过程
- 嵌入式|单片机有没有想象中那么好学,很迷茫有说正面有说负面
- STM32实验讲解|STM32控制舵机讲解,从入门到放弃。
- STM32|STM32通过IIC读取MPU6050原始数据过程详解
- stm32|STM32中iic驱动mpu6050例程
- #|【蓝桥杯嵌入式】【STM32】12_2020_第十一届_蓝桥杯_嵌入式设计与开发项目_省赛
- 单片机系列|嵌入式STM32开发中关键字_IO