一、硬件电路
这里以C相电压采集为例,来快速了解RN8302B的使用
?
?二、 配置工作
1、准备好printf工程,参考之前的教程
STM32CubeIDE实现printf重定向输出到串口_飞由于度的博客-CSDN博客STM32CubeIDE之printf重定向及串口https://blog.csdn.net/qq_35629563/article/details/126665838
2、配置RN8302B通信引脚
①SPI引脚
?
具体原因:
1)
2)?
?CPOL表示SCK空闲时间的状态,从时序图里可以看出CPOL=LOW
CPHA表示在第一边沿还是第二边沿进行数据交换,从时序图里可以看出CPOL=2 Edge
?②控制引脚
将PB12配置为GPIO_Output模式,PC6配置为GPIO_Input模式
?③呼吸灯
这里我是用的是PC1作为呼吸灯,其实不论使用哪个引脚控制的呼吸灯,只需将其重命名为LED1即可
3、引脚重命名
然后右击引脚分别重命名(注意顺序:先左击配置模式,再右击重命名)
?
最终结果
?
生成代码
?
三、代码编写
1、rn8302b.h
#ifndef _SPI_H_
#define _SPI_H_
#include "main.h"
#include "stdio.h"
//---------------------- RN8302计量寄存器地址定义---------------------------------------------------//
#define UC_CMD 0x0009//4//C相电压有效值
#define UC_BYTE 4
#define SYSSR_CMD 0x018A//系统状态寄存器
#define SYSSR_BYTE 2
#define DeviceID_CMD 0x018f//RN8302B Device ID
#define DeviceID_BYTE 3
#define SPI_CS_HIGH() HAL_GPIO_WritePin( RN_NSS_GPIO_Port , RN_NSS_Pin, GPIO_PIN_SET )
#define SPI_CS_LOW() HAL_GPIO_WritePin( RN_NSS_GPIO_Port , RN_NSS_Pin, GPIO_PIN_RESET )
void ReadAmmeterData(void);
#endif
2、rn8302b.c
/****************SPI 采用端口模拟**********************************/
#include "rn8302b.h"
#include "spi.h"
/*****************SPI 写单字节**************************/
void Write_SPI_OneByte(uint8_t TxData)
{
uint8_t Rxdata;
HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);
return ;
}
/*****************SPI 读单字节**************************/
uint8_t Read_SPI_OneByte(void)
{
uint8_t Rxdata;
uint8_t TxData=0;
HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000);
return Rxdata;
}
/************************* READ_RN8302*************************************************/
uint32_t READ_SPI(uint16_t Address,uint8_t Data_len)
{
uint8_t i, DTemp,CheckSumR;
uint32_t drData;
SPI_CS_LOW(); // 开启SPI传输
DTemp = (uint8_t)(Address&0x00FF);//ADDR[7:0]
CheckSumR = DTemp;
Write_SPI_OneByte(DTemp);
DTemp = (((uint8_t)(Address >> 4)) & 0xf0) ;//CMD=R/W+AD[10:8]+BL[1:0]+2’h0(MSB+LSB)
CheckSumR += DTemp;
Write_SPI_OneByte(DTemp);
HAL_Delay(5);
drData = 0x00000000;//Read 24bit
for(i=0;i<Data_len;i++)//先发高字节,后发低字节
{
DTemp = Read_SPI_OneByte();
drData = drData<<8;
drData += DTemp;
CheckSumR += DTemp;
}
CheckSumR = ~CheckSumR;//校验和算法: ADDR+CMD+DATA 单字节求和取反。
if (CheckSumR != Read_SPI_OneByte())//比较校验和
{
drData = 0xFFFFFFFF;
}
SPI_CS_HIGH(); //关闭SPI传输
HAL_Delay(2);
return drData;
}
/**************************Write RN8302******************************/
void Write_SPI(uint16_t Address, uint32_t dwData,uint8_t Date_len)
{
uint8_t i,CheckSumR, DTemp;
SPI_CS_LOW(); //开启SPI传输
DTemp = (uint8_t)(Address&0x00FF);//
CheckSumR = DTemp;
Write_SPI_OneByte(DTemp);//写地址
DTemp = (((uint8_t)(Address >> 4)) & 0xf0)+0x80 ;
CheckSumR += DTemp;
Write_SPI_OneByte(DTemp);//写命令
for (i =0 ;i < Date_len;i++)//先发高字节,后发低字节
{
DTemp = (uint8_t)(dwData>>(Date_len-1-i)*8);
Write_SPI_OneByte(DTemp);//写命令
CheckSumR += DTemp;
}
CheckSumR = ~CheckSumR;//校验和算法: ADDR+CMD+DATA 单字节求和取反。
Write_SPI_OneByte(CheckSumR);//写命令
SPI_CS_HIGH(); //结束传输
HAL_Delay(2);
}
void ReadAmmeterData(void)
{
uint32_t temp = 0;
temp = READ_SPI(DeviceID_CMD,DeviceID_BYTE);//芯片ID//supposed to be 0x00830200(hex)
printf("Device_ID=%x(hex)\r\n",(int)temp);
if(temp != 0x00830200) //读ID
{
printf("===================== \r\n");
printf("Device_ID!=0x00830200 \r\n");
printf("===================== \r\n");
return;
}
temp = READ_SPI(SYSSR_CMD,SYSSR_BYTE);//系统状态
printf("SYSSR=%x(hex)\r\n",(int)temp);
HAL_Delay(1000);
temp = READ_SPI(UC_CMD,UC_BYTE);//读取电压有效值
printf(" UC 寄存器有效值=%8X\r\n",(int)temp);
printf(" UC 引脚处有效值=%8.2f\r\n",(float)(temp/167772));
printf(" UC 端口处有效值=%8.2f\r\n",(float)(temp/167772*1.76));
}
3、main.c
在USER CODE BEGIN Includes下添加以下代码
#include <stdio.h>
#include <string.h>
#include "rn8302b.h"
uint8_t t=0;
在USER CODE BEGIN 3下添加以下代码
ReadAmmeterData();
HAL_Delay(3000);
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
printf("%d\r\n",++t);
四、实验结果
全部代码与RN8302B的手册
https://download.csdn.net/download/qq_35629563/86512618https://download.csdn.net/download/qq_35629563/86512618?
|