嘉立创产业服务站群
发作品签到
专业版

电流电压表

工程标签

528
0
0
0

简介

采用CW芯片,使用ADC和spi,实现电流电压的显示输出。

简介:采用CW芯片,使用ADC和spi,实现电流电压的显示输出。
电压电流表训练营【立创开发板&CW32】

开源协议

GPL 3.0

(未经作者授权,禁止转载)
创建时间:2024-07-18 01:38:36更新时间:2024-09-26 02:16:13

描述

项目简介

本项目是基于CW32的电流电压表。

项目功能

本设计是基于CW32单片机设计的电流电压表检测;采用0.96寸OLED屏幕显示检测的电流电压;采用分压电路扩大检测的电压电流范围;按键切换模式;点灯科技用于指示状态。

项目参数

  • 本设计采用CW32主控芯片,带有内部基准,ADC采集准确;
  • 本设计采用0.96寸OLED显示,实时刷新显示电流电压;
  • 采用分压电路,扩大测量范围;

原理解析(硬件说明)

本项目由以下部分组成,电源部分、LED指示、主控部分、ADC采集、OLED显示部分,本项目主要是通过ADC采集后并进行处理,显示在OELD屏幕上。
1--主控电路:
采用CW32芯片,引出串口,方便调试

image.png
2--电源电路:
采用TYPE-C-16P接口作为供电接口,加入了防反接。

image.png
3--OLED显示电路:
使用0.96寸OLED显示屏,教程多,方便显示移植。

image.png
4--ADC采集电路
采用分压电路,扩大范围。

image.png
5--基准电路
提供基准,使得测量更准。

image.png
6--校准电路
因测量电路存在误差,采用校准电路,后面可以进行校准。

image.png

软件代码

1--使用了RT-Thread 操作系统,移植了极小内核版本,对接了finsh。

void rt_hw_console_output(const char *str)
{
	rt_size_t i = 0, size = 0;
	size= rt_strlen(str);
	for(i=0 ; i < size ;i++)
	{
    if (*str == '\n')
    {
			 USART_ClearFlag(CW_UART1, USART_FLAG_TC);
       USART_SendData_8bit(CW_UART1, '\r');
	     while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TC)== RESET);
    }
		USART_ClearFlag(CW_UART1, USART_FLAG_TC);
		USART_SendData_8bit(CW_UART1, *(str++));
	
	  while(USART_GetFlagStatus(CW_UART1, USART_FLAG_TC)== RESET);			
	}
}
int rt_hw_console_getchar(void)
{
    int ch = -1;
		while (USART_GetFlagStatus(CW_UART1, USART_FLAG_RC) == RESET);
	
		USART_ClearFlag(CW_UART1, USART_FLAG_RC);
		
		if (USART_GetFlagStatus(CW_UART1, USART_FLAG_PE | USART_FLAG_FE))
		{
				USART_ClearFlag(CW_UART1, USART_FLAG_PE | USART_FLAG_FE);
				 rt_thread_mdelay(10);
		}
		else
		{
				ch=	USART_ReceiveData_8bit(CW_UART1);
		
		}
		 return ch;
  
}

2--OELD显示
采用了硬件SPI,也移植U8G2,移植OLED可以参考立创移植手册。

uint8_t u8x8_byte_4wire_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
    void *arg_ptr)
{
	uint8_t *data = (uint8_t *)arg_ptr;
  switch (msg)
  {
		case U8X8_MSG_BYTE_SEND:
		{
			for(int i = 0; i < arg_int; i++)
		spi_read_write_byte((u8)*(data + i));
	
    break;
		}

  case U8X8_MSG_BYTE_INIT:
    break;
  case U8X8_MSG_BYTE_SET_DC:
		
	if ( arg_int ) GPIO_WritePin(OLED_GPIO_PORT,OLED_DC_PIN, GPIO_Pin_SET);
            else  GPIO_WritePin(OLED_GPIO_PORT,OLED_DC_PIN, GPIO_Pin_RESET);

    break;
  case U8X8_MSG_BYTE_START_TRANSFER:

		GPIO_WritePin(OLED_GPIO_PORT,OLED_CS_PIN, GPIO_Pin_RESET);
  break;
  case U8X8_MSG_BYTE_END_TRANSFER:

		GPIO_WritePin(OLED_GPIO_PORT,OLED_CS_PIN, GPIO_Pin_SET);
    break;
		default:
    return 0;
  }
  return 1;
}

3--ADC采集
ADC采集后,进行滤波处理后输出。

void ADC_init(void)
{
  ADC_InitTypeDef     ADC_InitStructure;         //ADC配置结构体
  ADC_SerialChTypeDef ADC_SerialChStructure;     //ADC序列通道结构体
  GPIO_InitTypeDef    GPIO_Init_Struct;

  __RCC_GPIOB_CLK_ENABLE(); //打开ADC对应引脚时钟
  __RCC_ADC_CLK_ENABLE();   // 打开ADC时钟


	
  PB00_ANALOG_ENABLE();                    //使能模拟引脚
	PB01_ANALOG_ENABLE();                    //使能模拟引脚
	PB10_ANALOG_ENABLE();                    //使能模拟引脚
	PB11_ANALOG_ENABLE();                    //使能模拟引脚
  ADC_StructInit(&ADC_InitStructure);      // ADC默认值初始化
  ADC_InitStructure.ADC_ClkDiv     = ADC_Clk_Div128; //ADC工作时钟配置 PCLK/4 = 6/4 = 1.5Mhz
//	ADC_SerialChStructure.ADC_InitStruct.ADC_AccEn = ADC_AccDisable;   //转换结果累加不使能
//	ADC_SerialChStructure.ADC_InitStruct.ADC_Align = ADC_AlignLeft;   //ADC转换结果右对齐
//	ADC_SerialChStructure.ADC_InitStruct.ADC_DMAEn = ADC_DmaDisable;   //关闭DMA传输
//  ADC_SerialChStructure.ADC_InitStruct.ADC_SampleTime = ADC_SampTime5Clk;   //5个ADC时钟周期
//	ADC_SerialChStructure.ADC_InitStruct.ADC_InBufEn = ADC_BufEnable;  //开启跟随器
//	ADC_SerialChStructure.ADC_InitStruct.ADC_TsEn = ADC_TsEnable;    //内置温度传感器禁用
//  ADC_SerialChStructure.ADC_InitStruct.ADC_OpMode = ADC_SerialChScanMode;   //序列扫描模式:4个通道同时转换一次
/*信号电压较低时,可以降低参考电压来提高分辨率。 改变参考电压后,同样二进制表示的电压值就会不一样,
  最大的二进制(全1)表示的就是你的参考电压,在计算实际电压时,就需要将参考电压考虑进去。*/
  ADC_InitStructure.ADC_VrefSel    = ADC_Vref_BGR1p5;     //参考电压设置为1.5V
  ADC_InitStructure.ADC_SampleTime = ADC_SampTime10Clk;   //由于电压信号为慢速信号,ADC采样时间为十个ADC采样周期以确保准确
  
	ADC_SerialChStructure.ADC_Sqr0Chmux = ADC_SqrCh8;     //通道4输入PB00
	ADC_SerialChStructure.ADC_Sqr1Chmux = ADC_SqrCh9;      //通道13输入
	ADC_SerialChStructure.ADC_Sqr2Chmux = ADC_SqrCh11;        //通道11输入
	ADC_SerialChStructure.ADC_Sqr3Chmux = ADC_SqrCh12;       //通道12输入
	ADC_SerialChStructure.ADC_SqrEns  = ADC_SqrEns03;     //Sqr为序列配置寄存器,这里只用到了序列0的通道,所以配置成0表示只转换Sqr0序列
  ADC_SerialChStructure.ADC_InitStruct = ADC_InitStructure; //ADC初始化
	ADC_SerialChContinuousModeCfg(&ADC_SerialChStructure);   //ADC序列连续转换模式配置

  
	ADC_ClrAccResult();
	ADC_ClearITPendingAll();           //清除ADC所有中断状态
  ADC_Enable();                      // ADC使能
  ADC_SoftwareStartConvCmd(ENABLE);  //ADC转换软件启动命令
}

uint32_t Mean_Value_Filter(uint16_t *value, uint32_t size)     //均值滤波
{
    uint32_t sum = 0;
    uint16_t max = 0;
    uint16_t min = 0xffff;
    int      i;

    for(i = 0; i < size; i++)  //遍历数组找到最大值和最小值
    {
      sum += value[i];
      if(value[i] > max)
      {
        max = value[i];
      }
      if(value[i] < min)
      {
        min = value[i];
      }
    }
    sum -= max + min;         //减去最大和最小值后求平均
    sum  = sum / (size - 2);
    return sum;
}

4--保存标定
进行标定后,把相应值锁存在flash,防止重新上电后值改变,这里电压和电流的K值用了函数。写入时注意先擦除再写入,否则写入错误

void flash_erase(void)
{
    uint8_t Flag;
    // erase
    FLASH_UnlockPages(START_ADDR, END_ADDR);       // 解锁最后一个页面
    Flag = FLASH_ErasePages(START_ADDR, END_ADDR); // 擦除最后一个页面
    FLASH_LockAllPages();
  
}

void flash_write(uint16_t offset,uint16_t *data,uint16_t lenght)
{
    uint8_t Flag;
    // write
    FLASH_UnlockPages(START_ADDR, END_ADDR); // 解锁最后一个页面
    Flag = FLASH_WirteHalfWords(START_ADDR+offset*2, data, lenght);
    FLASH_LockAllPages();
   
}
void ComputeKV()
{
		flash_read(0,k_data,4);
		flash_erase();	
		k_data[0]=cal_adc.span_v[1]-cal_adc.span_v[0];
		k_data[0]= (k_data[0]/(V_15-V_05));//电压
		k_data[2] = 8;
		flash_write(0,k_data,4);
}
void ComputeKI()
{
		flash_read(0,k_data,4);
		flash_erase();	
		k_data[1]=cal_adc.span_m[1]-cal_adc.span_m[0];
	  k_data[1]= (k_data[1]/(M_15-M_05));//电流
	
		k_data[3]=8;
		flash_write(0,k_data,4);	
}

功能说明

1.主界面显示的电流测量范围是03A,电压范围是03V,VMAX的范围是0~30V,与硬件电路的测量测量范围一一对一;
2.按键说明:
(1)K1主界面切换;
(2)K2点击界面显示标定模式,进入标定;
(3)K3电流/电压标定,点击切换;
(4)K4第一次点击进入标定第一个点,再次点击,记录标定值,结束;
(5)K4第一次点击进入标定第二个点,再次点击,记录标定值,结束;
(6)两个点标定后,点击K6,计算出K值,标定结束;
(7)每个按键对应一个指示灯。

实物展示

测量5V电压,3V电路显示3V,满量程,30V量程显示有误差为5.1V

dfe1fe0b30a88571cda6bffa63fb5a4.jpg

后续优化

  • OLED设计成多级界面;
  • 使用按键进行切换(留有6个按键,无需更改硬件);

附件清单

1.CWF030是源码;
2.C5138758是OED屏幕规格书,里面有驱动流程;
3.PCtoLCD2002是常用的取模软件。

设计图

未生成预览图,请在编辑器重新保存一次

BOM

暂无BOM

附件

序号文件名称下载次数
1
CW32F030.zip
51
2
C5139758_OLED显示屏_HS96L01W4S03_规格书_WJ635575.PDF
8
3
PCtoLCD2002.zip
7
克隆工程
添加到专辑
0
0
分享
侵权投诉

评论

全部评论(1)
按时间排序|按热度排序
粉丝0|获赞0
相关工程
暂无相关工程

底部导航