前言
做之前信誓旦旦,这个小玩意,还不是分分钟拿捏???
做之后呢,分分钟被拿捏,真的是赢了李工那句话,这个东西说难不难,做好了却不容易。
真的是想做的很精确,的确真的是太难了,尤其电流测量,此话后说。
总之,越是看着简单的东西,做起来反而不是得心应手。
最后感谢各位大佬哦,感谢立创给我这个机会。这次是我最让我印象深刻的,坑太多了。
原理介绍
所谓功率计,就是计算电子产品的功耗。一般以瓦,毫瓦为单位。
需要测量2个数据,第一是电压u,也就是电压降。
需要测量的第二个数据就是电流i.
那么功率P=u*i。原理就是这么简单哦。
看起来简单,做起来可不简单哦。
硬件设计:
下面将整个电路进行分部介绍
主控芯片
这次选择是CW32F030C8T6。这个ARM M0内核的芯片有如下特点:
• 内核:ARM® Cortex®-M0+
-
最高主频 64MHz
• 工作温度:-40℃ 至 105℃;工作电压:1.65V 至 5.5V
• 存储容量
-
最大 64K 字节 FLASH,数据保持 25 年 @85℃
-
最大 8K 字节 RAM,支持奇偶校验
-
128 字节 OTP 存储器•
CRC 硬件计算单元
复位和电源管理
-
低功耗模式(Sleep,DeepSleep)
-
上电和掉电复位(POR/BOR)
-
可编程低电压检测器(LVD)
• 时钟管理
-
4 ~ 32MHz 晶体振荡器
-
32kHz 低速晶体振荡器
-
内置 48MHz RC 振荡器
-
内置 32kHz RC 振荡器
-
内置 10kHz RC 振荡器
-
内置 150kHz RC 振荡器
-
内置 PLL 锁相环
-
时钟监测系统
-
允许独立关断各外设时钟
• 支持最多 39 路 I/O 接口
-
所有 I/O 口支持中断功能
-
所有 I/O 支持中断输入滤波功能•
五通道 DMA 控制器
模数转换器
-
12 位精度,±1 LSB
-
最高 1M SPS 转换速度
-
内置电压参考
-
模拟看门狗功能
-
内置温度传感器
• 双路电压比较器
• 实时时钟和日历
-
支持由 Sleep/DeepSleep 模式唤醒
定时器
-
16 位高级控制定时器,支持 6 路捕获 / 比较通道和 3 对互补 PWM 输出,死区时间和灵活的同步功能
-
四组 16 位通用定时器
-
三组 16 位基本定时器
-
窗口看门狗定时器
-
独立看门狗定时器
• 通信接口
-
三路低功耗 UART,支持小数波特率
-
两路 SPI 接口 12Mbit/s
-
两路 I2C 接口 1Mbit/s
-
IR 调制器
串行调试接口 (SWD)
该芯片功耗低,封装多样,也是国产的,价格优惠,大家可以优先选用哦。
本项目使用管脚不多,主要是控制如下接口
ADC:采用电源、电流
串口:调试打印:
IIC:控制显示屏幕
原理图如下:
电源部分
虽然是USB功率计,想了想,万一需要测量电压更大的,所以选用LDO是也考虑了一下,选择了如下LDO
最大支持12V输入。一般够用了。输出3.3V,最大800mA。这里也是为了以后自己多个固定输出3.3V的电压模块。
因此整体测量电压不要超过12V哦。
具体实现原理图如下:
显示屏
显示屏选用了0.91寸的白字屏。128X32,可以显示四行。
接口和尺寸如下:
这个是模块化的,内部电路如下,IIC不用上拉电阻了,模块自带。非常好用的。
因此本项目原理图设计只需要预留接口即可,如下所示:
电压采集电路
这里为了节省成本,直接采用了分压电路,如下图所示
注意:CW32社区建议VADC再接个电阻,我个人觉得有钱的话,自己用个运放电路就好,或者电压跟随电路,可以提高驱动能力,降低阻抗。这是个人建议。
VADC使用了PA1采样。
电流采集电路
这里通过串联小电阻的方式进行产生压降。然后使用TI的芯片INA199A3DCKR专门做电流感应放大器。这个有三种可选,我选择了200倍的。大家若是测量小电流的选择50或100倍的。对应的型号如下
我选择的这个A3的200倍,配合CW32的ADC采用参考电压2.5V的,这个是CWF030内部配置,其实还有3.3V、1.5V供选择,那么我选择了2.5V。则最大电流
Imax=2.5/200/0.01=1.25A。对于常用的电脑USB口,这个值足够了。
若是大家觉得太大或者太小,可以选择不同的放大器配合不同的电压基准。比如我若选择3.3V,则Imax=1.65A了,那么测试小电流就没有准确了。范围越小测量越准,大家参考这个准则吧。
**根据之前的最大电压12V,因此这个带负载功率Pmax=12*1.25=15W。千万不能再大。再大可能冒烟了。**
原理设计如下:
指示灯
这里使用了彩灯,ws2812,最近比较流行个,比较炫酷,电路很简单,如下。
程序还没来得及写驱动,等第二版再更新软件吧。
其它下载、复位、模式电路
这里只说一下复位电路,由于DAP调试,不能软复位,还是最好留下个复位硬件接口,或者直接跟下载器的RST连接,否则比较麻烦啊。
具体原理图如下:
软件实现
也分成几个部分说明一下吧
显示部分
主要是IIC的驱动,SSD106直接参考官方初始化函数即可。
流程图如下
OLED初始化函数如下:
至于我们使用需要文字或图片,采用取模软件即可。
详细代码太长了,这里就不贴了。相关函数可以看下
ADC采集部分
这里使用了管脚PA1和PA2分别采集电压和电流,相关文件若需要修改的,最好看对着手册自己写吧,这里适合直接复刻。
在这部分,卡的太久了,各种不对,各种坑。总之,大家认真的对待吧。
相关配置函数如下:
#ifndef __ADC_H
#define __ADC_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "base_types.h"
#include "cw32f030.h"
#include "system_cw32f030.h"
#include "interrupts_cw32f030.h"
#include "cw32f030_systick.h"
#include "cw32f030_rcc.h"
#include "cw32f030_gpio.h"
#include "cw32f030_adc.h"
extern uint16_t gAdcResult[4];
void ADC_Config(void);
uint8_t Gain_Value(void);
#ifdef __cplusplus
}
#endif
#endif /* __ADC_H */
adc.c实现文件如下:
/******************************************************************************
/******************************************************************************
/* 序列通道连续采样模式 */
//#define SQR_CONTINUOUS_MODE_EN
/* 序列通道扫描采样模式 */
#define SQR_SCAN_MODE_EN
/* 序列通道多次采样模式 */
//#define SQR_MORE_MODE_EN
/* 序列通道断续采样模式 */
//#define SQR_BREAK_MODE_EN
/* USER CODE END EM */
/******************************************************************************
/******************************************************************************
/******************************************************************************
/******************************************************************************
-
Local variable definitions ('static') *
******************************************************************************/
uint16_t valueAdc;
uint16_t gAdcResult[4];
uint32_t valueAdcAcc;
volatile uint8_t gFlagIrq;
uint16_t gCntEoc = 0;
uint8_t cntSample;
/******************************************************************************
/*****************************************************************************
/**
- [url=home.php?mod=space&uid=2666770]@Brief[/url] ADC I/O初始化
*/
void ADC_PortInit(void)
{
//打开GPIO时钟
REGBITS_SET(CW_SYSCTRL->AHBEN, SYSCTRL_AHBEN_GPIOA_Msk);
//打开ADC时钟
REGBITS_SET(CW_SYSCTRL->APBEN2, SYSCTRL_APBEN2_ADC_Msk);
//set PA01 as AIN1 INPUT
PA01_ANALOG_ENABLE();
//set PA02 as AIN2 INPUT
PA02_ANALOG_ENABLE();
// //set PA05 as AIN5 INPUT
// PA06_ANALOG_ENABLE();
// //set PA07 as AIN7 INPUT
// PA07_ANALOG_ENABLE();
}
void ADC2_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_SerialChTypeDef ADC_SerialChStructure;
//配置ADC测试IO口
ADC_PortInit();
//ADC初始化
// ADC_InitStructure.ADC_SampleTime=ADC_SampTime10Clk;
// ADC_InitStructure.ADC_VrefSel=ADC_Vref_BGR1p5;
ADC_StructInit(&ADC_InitStructure);
//ADC工作时钟配置
#ifdef SQR_BREAK_MODE_EN
ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div1;
#else
ADC_InitStructure.ADC_ClkDiv = ADC_Clk_Div16;
#endif
//ADC序列扫描转换模式配置
ADC_SerialChStructure.ADC_Sqr0Chmux = ADC_SqrCh1;//ADC_SqrVddaDiV3; //ADC_SqrCh1;
ADC_SerialChStructure.ADC_Sqr1Chmux = ADC_SqrCh2; //ADC_SqrCh2; //
// ADC_SerialChStructure.ADC_Sqr2Chmux = ADC_SqrCh6; //ADC_SqrCh5;
// ADC_SerialChStructure.ADC_Sqr3Chmux = ADC_SqrCh7;
ADC_SerialChStructure.ADC_SqrEns = ADC_SqrEns01;
ADC_SerialChStructure.ADC_InitStruct = ADC_InitStructure;
#ifdef SQR_CONTINUOUS_MODE_EN
/* 序列通道连续采样模式 */
ADC_SerialChContinuousModeCfg(&ADC_SerialChStructure);
ADC_ITConfig(ADC_IT_EOS, ENABLE);
#elif defined (SQR_SCAN_MODE_EN)
/* 序列通道扫描采样模式 */
ADC_SerialChScanModeCfg(&ADC_SerialChStructure);
ADC_ITConfig(ADC_IT_EOS, ENABLE);
#elif defined (SQR_MORE_MODE_EN)
/* 序列通道多次采样模式 */
cntSample = 0xFF; //转换次数为0xFF + 1次.
ADC_SerialChMoreModeCfg(&ADC_SerialChStructure, cntSample);
ADC_ITConfig(ADC_IT_EOC | ADC_IT_EOA, ENABLE);
#elif defined (SQR_BREAK_MODE_EN)
/* 序列通道断续采样模式 */
ADC_SerialChBreakModeCfg(&ADC_SerialChStructure);
ADC_ITConfig(ADC_IT_EOC | ADC_IT_EOS, ENABLE);
#else
#error "Please select ADC's running mode first in main.h!"
#endif
//ADC_ITConfig(ADC_IT_EOC | ADC_IT_EOS | ADC_IT_EOA, ENABLE);
ADC_EnableIrq(ADC_INT_PRIORITY);
ADC_ClearITPendingAll();
//ADC使能
ADC_Enable();
ADC_SoftwareStartConvCmd(ENABLE);
}
uint8_t Gain2_Value(void)
{
uint8_t temp=0;
#ifdef SQR_CONTINUOUS_MODE_EN
/* 序列通道连续采样模式 */
while (!(gFlagIrq & ADC_ISR_EOS_Msk));
gFlagIrq = 0u;
//while(!(gFlagIrq & ADC_ISR_EOS_Msk));
ADC_GetSqr0Result(gAdcResult);
ADC_GetSqr1Result(&gAdcResult[1]);
// ADC_GetSqr2Result(&gAdcResult[2]);
// ADC_GetSqr3Result(&gAdcResult[3]);
//printf("ch1:%5d-ch2:%5d-ch6:%5d-ch7:%5d\r\n",gAdcResult[0],gAdcResult[1],gAdcResult[2],gAdcResult[3]);
#elif defined (SQR_SCAN_MODE_EN)
/* 序列通道扫描采样模式 */
while (!(gFlagIrq & ADC_ISR_EOS_Msk));
gFlagIrq = 0u;
ADC_GetSqr0Result(gAdcResult);
ADC_GetSqr1Result(&gAdcResult[1]);
// ADC_GetSqr2Result(&gAdcResult[2]);
// ADC_GetSqr3Result(&gAdcResult[3]);
//printf("ch1:%5d-ch2:%5d-ch6:%5d-ch7:%5d\r\n",gAdcResult[0],gAdcResult[1],gAdcResult[2],gAdcResult[3]);
#elif defined (SQR_MORE_MODE_EN)
/* 序列通道多次采样模式 */
while (!(gFlagIrq & ADC_ISR_EOA_Msk));
gFlagIrq = 0u;
ADC_GetSqr0Result(gAdcResult); //Get data.
ADC_GetSqr1Result(&gAdcResult[1]);
// ADC_GetSqr2Result(&gAdcResult[2]);
// ADC_GetSqr3Result(&gAdcResult[3]);
ADC_GetAccResult(&valueAdcAcc);
if (gCntEoc != (cntSample + 1))
{
temp=1;
}
//printf("ch1:%5d-ch2:%5d-ch6:%5d-ch7:%5d\r\n",gAdcResult[0],gAdcResult[1],gAdcResult[2],gAdcResult[3]);
gCntEoc = 0u;
#elif defined (SQR_BREAK_MODE_EN)
/* 序列通道断续采样模式 */
while (!(gFlagIrq & ADC_ISR_EOC_Msk));
gFlagIrq &= (~ADC_ISR_EOC_Msk);
if (gFlagIrq & ADC_ISR_EOS_Msk)
{
gFlagIrq = 0u;
ADC_GetSqr0Result(gAdcResult);
ADC_GetSqr1Result(&gAdcResult[1]);
// ADC_GetSqr2Result(&gAdcResult[2]);
// ADC_GetSqr3Result(&gAdcResult[3]);
//printf("ch1:%5d-ch2:%5d-ch6:%5d-ch7:%5d\r\n",gAdcResult[0],gAdcResult[1],gAdcResult[2],gAdcResult[3]);
}
#endif
#ifndef SQR_CONTINUOUS_MODE_EN
ADC_SoftwareStartConvCmd(ENABLE); //启动下一次ADC转换
#endif
return temp;
}
串口输出实现
为了实现调试方便,实现串口1,print输出等。
实现函数如下
/******************************************************************************
-
Include files
******************************************************************************/
#include "uart1.h"
/******************************************************************************
-
Local pre-processor symbols/macros ('#define')
******************************************************************************/
//UARTx
#define DEBUG_USARTx CW_UART1
#define DEBUG_USART_CLK RCC_APB2_PERIPH_UART1
#define DEBUG_USART_APBClkENx RCC_APBPeriphClk_Enable2
#define DEBUG_USART_UclkFreq 8000000
//UARTx GPIO
#define DEBUG_USART_GPIO_CLK RCC_AHB_PERIPH_GPIOA
#define DEBUG_USART_TX_GPIO_PORT CW_GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_PIN_8
#define DEBUG_USART_RX_GPIO_PORT CW_GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_PIN_9
//GPIO AF
#define DEBUG_USART_AFTX PA08_AFx_UART1TXD()
#define DEBUG_USART_AFRX PA09_AFx_UART1RXD()
/******************************************************************************
-
Local variable definitions ('static') *
******************************************************************************/
#ifdef GNUC
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* GNUC */
/******************************************************************************
-
Local pre-processor symbols/macros ('#define')
******************************************************************************/
/**
-
@brief Retargets the C library printf function to the USART.
*/
PUTCHAR_PROTOTYPE
{
USART_SendData_8bit(DEBUG_USARTx, (uint8_t)ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return ch;
}
/**
*/
void UART1_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC\\_AHBPeriphClk\\_Enable\\(DEBUG\\_USART\\_GPIO\\_CLK\\, ENABLE\\);
DEBUG_USART_APBClkENx(DEBUG_USART_CLK, ENABLE);
//UART TX RX 复用
DEBUG_USART_AFTX;
DEBUG_USART_AFRX;
GPIO_InitStructure.Pins = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pins = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
}
/**
*/
void UART1_Configuration(uint32_t BaudRate)
{
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = BaudRate;
USART_InitStructure.USART_Over = USART_Over_16;
USART_InitStructure.USART_Source = USART_Source_PCLK;
USART_InitStructure.USART_UclkFreq = DEBUG_USART_UclkFreq;
USART_InitStructure.USART_StartBit = USART_StartBit_FE;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USARTx, &USART_InitStructure);
}
/**
-
@brief 发送8位数组
-
[url=home.php?mod=space&uid=3142012]@param[/url] USARTx :USARTx外设
-
参数可以是:
-
CW_UART1、CW_UART2、CW_UART3
-
@param TxBuf :待发送的数组
-
@param TxCnt :待发送的数组元素个数
*/
void UART1_SendBuf_Polling(uint8_t *TxBuf, uint8_t TxCnt)
{
while (TxCnt)
{
USART_SendData_8bit(CW_UART1, *TxBuf);
while (USART_GetFlagStatus(CW_UART1, USART_FLAG_TXE) == RESET);
TxBuf++;
TxCnt--;
}
while (USART_GetFlagStatus(CW_UART1, USART_FLAG_TXBUSY) == SET);
}
/**
-
@brief 接收8位数组
-
@param USARTx :USARTx外设
-
参数可以是:
-
CW_UART1、CW_UART2、CW_UART3
-
@param RxBuf :接收Buf
-
[url=home.php?mod=space&uid=1141835]@Return[/url] uint8_t :接收的字符个数
*/
uint8_t UART1_RecvBuf_Polling(uint8_t *RxBuf)
{
uint8_t RxCnt = 0;
do
{
//等待RC
while (USART_GetFlagStatus(CW_UART1, USART_FLAG_RC) == RESET);
//清RC
USART_ClearFlag(CW_UART1, USART_FLAG_RC);
//ERROR: PE or FE
if (USART_GetFlagStatus(CW_UART1, USART_FLAG_PE | USART_FLAG_FE))
{
USART_ClearFlag(CW_UART1, USART_FLAG_PE | USART_FLAG_FE);
RxCnt = 0x00;
}
else
{
RxBuf[RxCnt] = USART_ReceiveData_8bit(CW_UART1);
RxCnt++;
}
}
while (RxBuf[RxCnt - 1] != '\n');
return RxCnt;
}
效果如下:
主控函数
按照如下顺序执行
首先,初始化各种配置。时钟、GPIO、串口、屏幕配置等。
然后是数据采集和屏幕刷新循环进行,中间加了500ms的延时函数。
具体代码如下:
/******************************************************************************/
/** \file main.c
**
** A detailed description is available at
** [url=home.php?mod=space&uid=41289]@Link[/url] Sample Group Some description @endlink
**
** - 2021-03-12 1.0 xiebin First version for Device Driver Library of Module.
**
******************************************************************************/
/*******************************************************************************
- 代码许可和免责信息
- 武汉芯源半导体有限公司授予您使用所有编程代码示例的非专属的版权许可,您可以由此
- 生成根据您的特定需要而定制的相似功能。根据不能被排除的任何法定保证,武汉芯源半
- 导体有限公司及其程序开发商和供应商对程序或技术支持(如果有)不提供任何明示或暗
- 含的保证或条件,包括但不限于暗含的有关适销性、适用于某种特定用途和非侵权的保证
- 或条件。
- 无论何种情形,武汉芯源半导体有限公司及其程序开发商或供应商均不对下列各项负责,
- 即使被告知其发生的可能性时,也是如此:数据的丢失或损坏;直接的、特别的、附带的
- 或间接的损害,或任何后果性经济损害;或利润、业务、收入、商誉或预期可节省金额的
- 损失。
- 某些司法辖区不允许对直接的、附带的或后果性的损害有任何的排除或限制,因此某些或
- 全部上述排除或限制可能并不适用于您。
*******************************************************************************/
/******************************************************************************
-
Include files
******************************************************************************/
#include "main.h"
/******************************************************************************
-
Local pre-processor symbols/macros ('#define')
******************************************************************************/
/******************************************************************************
-
Global variable definitions (declared in header file with 'extern')
******************************************************************************/
extern uint16_t gAdcResult[4];
/******************************************************************************
-
Local type definitions ('typedef')
******************************************************************************/
/******************************************************************************
/******************************************************************************
-
Local variable definitions ('static') *
******************************************************************************/
uint8_t TxRxBufferSize;
uint8_t TxRxBuffer[] = "\r\nCW32F030 UART Polling\r\n";
/******************************************************************************
-
Local pre-processor symbols/macros ('#define')
******************************************************************************/
/*****************************************************************************
/**
** \brief Main function of project
**
** \return uint32_t return value, if needed
**
******************************************************************************/
int32_t main(void)
{
uint8_t flag=0;
float x,y,z;
//char s[20];
//SYSCLK = HSI = 8MHz = HCLK = PCLK
RCC_HSI_Enable(RCC_HSIOSC_DIV6);
//配置GPIO
UART1_GPIO_Configuration();
//配置UART
UART1_Configuration(9600);
OLED_Init(); //初始化OLED
OLED_Clear();
OLED\\_ShowString\\(20\\,1\\,"My Power Calc"\\,8\\,1\\);//6\\*8
UART1_SendBuf_Polling(TxRxBuffer, ARRAY_SZ(TxRxBuffer) - 1);
for(uint8_t i=0;i<3;i++)
{
delay1ms(500);
printf("hello kwin\r\n");
}
ADC2_Config();
while (1)
{
char s[20];
flag=Gain2_Value();
if(!flag)
{
printf\\("\\r\\nch1:%5d\\-ch2:%5d\\-ch6:%5d\\-ch7:%5d\\r\\n"\\,gAdcResult\\[0\\]\\,gAdcResult\\[1\\]\\,gAdcResult\\[2\\]\\,gAdcResult\\[3\\]\\);
//printf\\("ch1:%5d\\r\\n"\\,gAdcResult\\[0\\]\\);
x=gAdcResult\\[0\\]/4095\\.0\\*25;
sprintf\\(s\\,"U=%6\\.3fV"\\,x\\);
printf\\("\\r\\nU=%6\\.3fV\\n"\\,x\\);
OLED\\_ShowString\\(40\\,9\\,s\\,8\\,1\\);//6\\*8
//printf\\("ch2=%5d\\r\\n"\\,gAdcResult\\[1\\]\\);
y=gAdcResult\\[1\\]/4095\\.0\\*1\\.25;
sprintf\\(s\\,"I=%6\\.3fA"\\,y\\);
printf\\("I=%6\\.3fA\\r\\n"\\,y\\);
OLED\\_ShowString\\(40\\,17\\,s\\,8\\,1\\);//6\\*8
z=x\\*y;
sprintf\\(s\\,"P=%6\\.3fW"\\,z\\);
OLED\\_ShowString\\(40\\,25\\,s\\,8\\,1\\);//6\\*8
\\}else\\{printf\\("Get Value failed \\r\\n"\\);\\}
OLED\\_DrawLine\\(0\\,0\\,127\\,0\\,1\\);
OLED\\_DrawLine\\(127\\,0\\,127\\,31\\,1\\);
OLED\\_DrawLine\\(0\\,0\\,0\\,31\\,1\\);
OLED\\_DrawLine\\(0\\,31\\,127\\,31\\,1\\);
OLED\\_DrawLine\\(0\\,31\\,127\\,31\\,1\\);
//OLED\\_DrawCircle\\(63\\,31\\,16\\);
OLED_Refresh();
delay1ms(500);
}
}
/**
*/
/******************************************************************************
-
EOF (not truncated)
******************************************************************************/
#ifdef USE_FULL_ASSERT
/**
-
@brief Reports the name of the source file and the source line number
-
where the assert_param error has occurred.
-
@param file: pointer to the source file name
-
@param line: assert_param error line source number
-
@retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
测试效果:
首先电压部分:测量比较准确,我这里采用单次测量,多次平均效果会更好,能稳定在mV级别的,别问我是怎么知道的,除了上面展示的代码,我还有各种残缺版本的,反正对精度进行了很深入的对比。
其次电流部分:这个在10个mA的情况下不是很准,100ma以上可以到1%的误差,100mA以下,可能在5%以上,各种不等吧。欢迎大家复刻然后进行电子负载进行对比实验。
关于功率整体还是比较准确的,用了进行大致的定量分析,还是比较方便的。
实际效果如下:
由于文章长度有限制,只能贴核心代码了。不过第二版应该很快就出了。
着急复刻的,可以先使用附件的.hex文件。着急需要源码的联系我吧,不着急的请耐心等我更新第二版哦。
总结
第一次接触CW32的芯片,对CW32的芯片有了初步认识,后续的工作学习中会进一步学习和运用国产芯片。感谢这个平台,感谢CW32,希望国产芯片越做越好。
由于明天就要出差了,赶在今天弄完了(2023年11月18日19:18:00)。
第二板硬件已经到了了,来不及截止日前搞好第二板了,不管软件还是硬件都还有提升的空间,有兴趣的一起来DIY吧。
第二版直接做了PCB盖板效果应该好一些。为啥不打印壳?这还用问,都是太穷了哦。
PCB盖板还没有到,先看个效果图吧
B站链接
空载效果
https://www.bilibili.com/video/BV1T94y1H7KJ/?pop_share=1&vd_source=e36622a05269c0356d6cd566056a2488
负载梁山派效果
https://www.bilibili.com/video/BV1MH4y1q7Wp/?pop_share=1&vd_source=e36622a05269c0356d6cd566056a2488
负载加湿器效果
https://www.bilibili.com/video/BV1La4y1U74q/?pop_share=1&vd_source=e36622a05269c0356d6cd566056a2488