如何使用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_5void 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 寄存器,4000RX_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);                //在时钟上升沿,数据被写入CS5463addr <<= 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);            //在时钟上升沿,数据被写入CS5463dat <<= 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);                    //在时钟上升沿,数据被写入CS5463cmd <<= 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;                  //在时钟上升沿,数据被写入CS5463i++;}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(毫安)  12345maresult = 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,这里因为精度的原因,不+1RX_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,这里因为精度的原因,不+1RX_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;}

如何使用STM32F1/F4驱动CS5463相关推荐

  1. Arduino框架下STM32F1/F4系列HID模式程序烧录教程

    Arduino框架下STM32F1/F4系列HID模式程序烧录教程 相关篇<Arduino框架下STM32全系列开发固件安装指南> HID BootLoader烧录模式 "Upl ...

  2. STM32F1 TCA9548A 驱动多个IIC器件

    TCA9548A的用途就是IIC扩展,每个TCA9548A可以扩展出8路IIC.TCA9548A芯片带有地址选择引脚A0/A1/A2,根据高低电平不同,从MCU的一路IIC最多可以接入8个TCA954 ...

  3. STM32驱动LCD12864(串行模式)

    效果呈现 引脚定义:(VCC接入先询问厂家供电) PIN1--GND PIN2--5V PIN3--不接 PIN4--RS(CS) PIN5--R/W(SID) PIN6--E(SCK) PIN7-- ...

  4. 基于GD32VF103 的vga显示器 和ps2键盘 驱动

    基于GD32VF103的vga和ps2键盘驱动 前言 gd32vf103 是国内一款很不错的riscv架构微处理器,但是网上gd32vf103的应用还比较少,这里我决定分享一下利用这个微处理器制作的v ...

  5. STM32F1读取MLX90615非接触式红外温度传感器

    MLX90615 简介 MLX90615是一种红外温度计,用于非接触式温度测量.红外敏感热电堆探测器芯片和信号调节芯片集成在同一个TO-46 CAN封装中.由于采用了低噪声放大器.16位模数转换器和强 ...

  6. STM32F1读取MLX90632非接触式红外温度传感器

    MLX90632 简介 MLX90632是一个小型SMD SFN封装中的非接触式红外温度传感器,可实现高精度非接触式温度测量,.该装置在出厂时使用存储在EEPROM存储器中的校准常数进行校准.环境温度 ...

  7. 增量式编码器c语言,增量式编码器

    机器人运行过程中,电机转动会产生各种干扰信号.通过两组电源给机器人驱动系统和控制系统供电,以消除干扰对稳定性的影响. 码盘加陀螺仪的方法在应用过程中发现陀螺仪的角度会随着机械振动发生漂移,影响定位精度 ...

  8. 增量式编码器 绝对值编码器

    机器人运行过程中,电机转动会产生各种干扰信号.通过两组电源给机器人驱动系统和控制系统供电,以消除干扰对稳定性的影响. 码盘加陀螺仪的方法在应用过程中发现陀螺仪的角度会随着机械振动发生漂移,影响定位精度 ...

  9. 【程序】Marvell 88W8782/88W8801 WiFi模块创建或连接热点,并使用lwip2.1.3建立http服务器(20220213版)

    本程序所用的单片机型号为:STM32F103RE.STM32F407ZG或STM32H743ZI. 复位引脚(PDN)应连接到STM32F1/F4的PA15引脚或STM32H7的PE6引脚.不连接PD ...

  10. 本科/研究生阶段--嵌入式学习路线(尤其适用于机械僧)

    本科/研究生阶段--嵌入式学习路线(尤其适用于机械僧) 嵌入式开发方向 一.基础阶段(兴趣阶段) 2.1.知识储备 C语言 基本的数电模电 2.2.实践 Arduino开始入手 STM32F1/F4( ...

最新文章

  1. 【论文速读】RandLA-Net大规模点云的高效语义分割
  2. 全网最详细之一网打尽数据结构中与树相关的算法
  3. python中导入模块用什么命令_Python导入模块的技巧
  4. RGB565与RGB555位图文件格式的标志识别
  5. MySQL-InnoDB究竟如何巧妙实现,4种事务的隔离级别
  6. php使用imagemagick,PHP的ImageMagick使用;
  7. 浪潮服务器测试文档,ESXI6.7注入浪潮服务器raid驱动测试
  8. matlab实现层次分析法
  9. Android表格拖拽排序,Android 拖拽排序控件 DragGridView
  10. Linux netstat 命令查看80端口状态
  11. 基于springboot+vue的旅游信息(旅游线路)网站(前后端分离)
  12. 高交会|华创芯光邀您一起畅游可见光通信的世界
  13. Pygame实战:牛,几千行代码实现《机甲闯关冒险游戏》,太牛了(保存起来慢慢学)
  14. 国内最常用的坐标系大全
  15. NLP实战之textRNN中文文本分类
  16. win10禁用计算机维护,想要电脑不卡,你必须知道win10必须禁用的服务有哪些
  17. APP运营推广,如何做到“饱和攻击”
  18. windows10计算机里输入法,win10电脑上输入法不见了怎么办
  19. salt-stack部署
  20. 树莓派与DS18B20获取环境温度(Linux)

热门文章

  1. matlab lu解线性方程,LU分解和求解线性方程组
  2. 怎么把几个音频合并在一起?
  3. python编写一个简单的程序验证码_遇到验证码怎么办?Python编写一个验证码图片数据标注GUI程序!...
  4. 达梦数据库用户与模式
  5. PingTunnel隧道搭建
  6. python3使用MyQR库生成动态二维码
  7. tfidf关键词提取php,TFIDF介绍
  8. 一款好看的 VSCode 代码主题和图标主题
  9. 775针服务器cpu性能排行,e7500(775针cpu天梯图)
  10. Android 标题栏阴影大小,主题-XUI - Android 原生 UI 框架-面试哥