打印
[产品应用]

基于CW32L052电子秤设计

[复制链接]
4236|56
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lulugl|  楼主 | 2023-8-4 19:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 lulugl 于 2023-8-4 19:33 编辑

#申请原创# #有奖活动#[url=home.php?mod=space&uid=760190]@21小跑堂 [/url]
电子秤作为一种计量手段,广泛应用于工农业、科研、交通、内外贸易等各个领域,与人民的生活紧密相连。电子秤是电子衡器中的一种,衡器是国家法定计量器具,是国计民生、国防建设、科学研究、内外贸易不可缺少的计量设备,衡器产品技术水平的高低,将直接影响各行各业的现代化水平和社会经济效益的提高。称重装置不仅是提供重量数据的单体仪表,而且作为工业控制系统和商业管理系统的一个组成部分,推进了工业生产的自动化和管理的现代化,它起到了缩短作业时间、改善操作条件、降低能源和材料的消耗、提高产品质量以及加强企业管理、改善经营管理等多方面的作用。称重装置的应用已遍及到国民经济各领域,取得了显著的经济效益。
电子秤是称重技术中的一种新型仪表,广泛应用于各种场合。电子秤与机械秤比较有体积小、重量轻、结构简单、价格低、实用价值强、维护方便等特点,可在各种环境工作,重量信号可远传,易于实现重量显示数字化,易于与计算机联网,实现生产过程自动化,提高劳动生产率。从世界水平看,衡器技术已经经历了四个阶段,从传统的全部由机械元器件组成的机械称到用电子线路代替部分机械元器件的机电结合秤,再从集成电路式到目前的单片机系统设计的电子计价秤。我国电子衡器从最初的机电结合型发展到现在的全电子型和数字智能型。现今电子衡器制造技术及应用得到了新发展:电子称重技术从静态称重向动态称重发展;计量方法从模拟测量向数字测量发展;测量特点从单参数测量向多参数测量发展。常规的测试仪器仪表和控制装置被更先进的智能仪器所取代,使得传统的电子测量仪器在远离、功能、精度及自动化水平定方面发生了巨大变化,并相应的出现了各种各样的智能仪器控制系统,使得科学实验和应用工程的自动化程度得以显著提高。
电子称重的实现首先是通过压力传感器采集到被测物体的重量并将其转换成电压信号。输出电压信号通常很小,需要通过前端信号处理电路进行准确的线性放大。放大后的模拟电压信号经A/D转换电路转换成数字量被送入到主控电路的单片机中,再经过单片机控制译码显示器,从而显示出被测物体的重量。按照设计的基本要求,系统可分为三大模块,数据采集模块、控制器模块、人机交互液晶显示界面模块。其中数据采集模块由压力传感器、信号的前级处理和A/D转换部分组成。转换后的数字信号送给控制器处理,由控制器完成对该数字量的处理,驱动显示模块完成人机间的信息交换。此部分对软件的设计要求比较高,系统的大部分功能都需要软件来控制。
本次电子称的实现流程如下:

系统采用压电传感器是一种典型的有源传感器,又称自发电式传感器。其工作原理是基于某些材料受力后在其相应的特定表面产生电荷的压电效应。
压电传感器体积小、重量轻、结构简单、工作可靠,适用于动态力学量的测量,不适合测频率太低的被测量,更不能测静态量。目前多用于加速度和动态力或压力的测量。压电器件的弱点:高内阻、小功率。功率小,输出的能量微弱,电缆的分布电容及噪声干扰影响输出特性,这对外接电路要求很高。
电阻应变式传感器是一种利用电阻应变效应,将各种力学量转换为电信号的结构型传感器。电阻应变片式电阻应变式传感器的核心元件,其工作原理是基于材料的电阻应变效应,电阻应变片即可单独作为传感器使用,又能作为敏感元件结合弹性元件构成力学量传感器。
导体的电阻随着机械变形而发生变化的现象叫做电阻应变效应。电阻应变片把机械应变信号转换为△R/R后,由于应变量及相应电阻变化一般都很微小,难以直接精确测量,且不便处理。因此,要采用转换电路把应变片的△R/R变化转换成电压或电流变化。其转换电路常用测量电桥。
直流电桥的特点是信号不会受各元件和导线的分布电感及电容的影响,抗干扰能力强,但因机械应变的输出信号小,要求用高增益和高稳定性的放大器放大。
本次采用的如称重转感器如下图所示:

应变片式传感器有如下特点:
(1)应用和测量范围广,应变片可制成各种机械量传感器。
(2)分辨力和灵敏度高,精度较高。
(3)结构轻小,对试件影响小, 对复杂环境适应性强,可在高温、高压、强磁场等特殊环境中使用,频率响应好。
(4)商品化,使用方便,便于实现远距离、自动化测量[5]。
通过对压力传感器与电阻应变式传感器比较分析,最终选择了第二种方案。题目要求称重范围0~5Kg,满量程量误差不大于0.005Kg,考虑到秤台自重、振动和冲击分量,还要避免超重损坏传感器,所以传感器量程必须大于额定称重5Kg。我们选择的是电阻应变片压力传感器,量程为10Kg,精度为0.01% ,满足本系统的精度要求。
系统AD转换芯片选择
HX711是一款专为高精度电子秤而设计的24位A/D转换器芯片。与同类型其它芯片相比,该芯片集成了包括稳压电源、片内时钟振荡器等其它同类型芯片所需要的外围电路,具有集成度高、响应速度快、抗干扰性强等优点。降低了电子秤的整机成本,提高了整机的性能和可靠性。该芯片与后端MCU 芯片的接口和编程非常简单,所有控制信号由管脚驱动,无需对芯片内部的寄存器编程。输入选择开关可任意选取通道A 或通道B,与其内部的低噪声可编程放大器相连。通道A 的可编程增益为128 或64,对应的满额度差分输入信号幅值分别为±20mV或±40mV。通道B 则为固定的64 增益[[]9,用于系统参数检测。芯片内提供的稳压电源可以直接向外部传感器和芯片内的A/D 转换器提供电源,系统板上无需另外的模拟电源。芯片内的时钟振荡器不需要任何外接器件。上电自动复位功能简化了开机的初始化过程。芯片原理图如下所示

系统显示器选择
CW32L052开发板板载了8位段码LCD屏。
代码设计:
HX711.h
#ifndef __HX711_H
#define __HX711_H

#include "main.h"
#include "cw32l052_gpio.h"
#include "cw32L052_rcc.h"

//PF04 SCK
//PF05 DOUT
#define HX711_SCK  CW_GPIOF->ODR_f.PIN4
#define HX711_DOUT GPIO_ReadPin(CW_GPIOF, GPIO_PIN_5)


extern void Init_HX711pin(void);
extern uint32_t HX711_Read(void);
extern void Get_Maopi(void);
extern void Get_Weight(void);

extern uint32_t HX711_Buffer;
extern uint32_t Weight_Maopi;
extern int32_t Weight_Shiwu;
extern uint8_t Flag_Error;

#endif

HX711.c
/************************************************************************************
                                                
*************************************************************************************/
#include "HX711.h"


uint32_t HX711_Buffer;
uint32_t Weight_Maopi;
int32_t Weight_Shiwu;
uint8_t Flag_Error = 0;

//校准参数
//因为不同的传感器特性曲线不是很一致,因此,每一个传感器需要矫正这里这个参数才能使测量值很准确。
//当发现测试出来的重量偏大时,增加该数值。
//如果测试出来的重量偏小时,减小改数值。
//该值可以为小数
#define GapValue 212.5
void delay_1us(void)
{
        __NOP();
        __NOP();
}

void Init_HX711pin(void)
{
        __RCC_GPIOF_CLK_ENABLE();
        GPIO_InitTypeDef GPIO_InitStructure;


        //HX711_SCK
        GPIO_InitStructure.Pins = GPIO_PIN_4;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_Init(CW_GPIOF, &GPIO_InitStructure);

        GPIO_InitStructure.Pins = GPIO_PIN_5;
        GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
        GPIO_Init(CW_GPIOF, &GPIO_InitStructure);
        
        GPIO_SetBits(CW_GPIOF,GPIO_PIN_4);                                        //初始化设置为0
}



//****************************************************
//读取HX711
//****************************************************
uint32_t HX711_Read(void)        //增益128
{
        
        unsigned long count;
        unsigned char i;
          //HX711_DOUT=1;
                CW_GPIOF->ODR_f.PIN5 = 1;
        
          HX711_SCK=0;
          count=0;
          while(HX711_DOUT);
          for(i=0;i<24;i++)
        {
                  HX711_SCK=1;
                  count=count<<1;
                delay_1us();
                HX711_SCK=0;
                  if(HX711_DOUT)
                        count++;
                delay_1us();
        }
         HX711_SCK=1;
  count=count^0x800000;//第25个脉冲下降沿来时,转换数据
        delay_1us();
        HX711_SCK=0;  
        return(count);
}

//****************************************************
//获取毛皮重量
//****************************************************
void Get_Maopi(void)
{
        Weight_Maopi = HX711_Read();        
}

//****************************************************
//称重
//****************************************************
void Get_Weight(void)
{
        HX711_Buffer = HX711_Read();
        if(HX711_Buffer > Weight_Maopi)                        
        {
                Weight_Shiwu = HX711_Buffer;
                Weight_Shiwu = Weight_Shiwu - Weight_Maopi;                                //获取实物的AD采样数值。
        
                Weight_Shiwu = (int32_t)((float)Weight_Shiwu/GapValue);         //计算实物的实际重量
                                                                                                                                                //因为不同的传感器特性曲线不一样,因此,每一个传感器需要矫正这里的GapValue这个除数。
                                                                                                                                                //当发现测试出来的重量偏大时,增加该数值。
                                                                                                                                                //如果测试出来的重量偏小时,减小改数值。
        }

        
}

LCD

#include "lcd.h"

/* 段码低8(左) */
static const uint8_t num_L[19] = {
    0x0d, //0
    0x00, //1
    0x0e, //2
    0x0a, //3
    0x03, //4
    0x0b, //5
    0x0f, //6
    0x00, //7
    0x0f, //8
    0x0b, //9
    0x07, //A
    0x0f, //b
    0x0d, //C
    0x0e, //d
    0x0f, //E
    0x07, //F
    0x07, //H
    0x0d, //L
    0x02, //-
};
/* 段码高8(右) */
static const uint8_t num_H[19] = {
    0x07,
    0x06,
    0x03,
    0x07,//3
    0x06,//4
    0x05, //5
    0x05, //
    0x07, //7
    0x07, //8
    0x07, //9
    0x07, //A
    0x04, //B
    0x01, //C
    0x06, //d
    0x01, //e
    0x01, //f
    0x06, //H/*
    0x00, //L
    0x00, //-
};

/* 函数功能:在指定的段码屏位置上显示指定序号的字符
*参数wei:
   指定需要显示的位
*参数num:
   需要显示的序号。
   */
void lcd_show_string(uint8_t wei, uint8_t num)
{
    if(wei>7 || num > sizeof(num_H))
    {
        return;
    }
    switch(wei)
    {
    case 7:
    {
//显示第7个数码管
        CW_LCD->RAM[0] |= num_H[num]<<8 | num_L[num];

        break;
    }
    case 6:
    {
//显示第6个数码管
        CW_LCD->RAM[0] |= (num_H[num]<<8 | num_L[num]) <<16;
        break;
    }
    case 5:
    {
//显示第5个数码管
        CW_LCD->RAM[1] |= num_H[num]<<8 | num_L[num];
        break;
    }
    case 4:
    {
//显示第4个数码管
        CW_LCD->RAM[1] |= (num_H[num]<<8 | num_L[num]) <<16;
        break;
    }
    case 3:
    {
//显示第3个数码管
        CW_LCD->RAM[2] |= num_H[num]<<8 | num_L[num];
        break;
    }
    case 2:
    {
//显示第2个数码管
        CW_LCD->RAM[3] |= (num_H[num]<<8);
        CW_LCD->RAM[2] |= (num_L[num]<<16);
        break;
    }
    case 1:
    {
//显示第1个数码管
        CW_LCD->RAM[3] |= num_H[num]<<24 | num_L[num]<<16;
        break;
    }
    case 0:
    {
//显示第0个数码管
        CW_LCD->RAM[4] |= (num_H[num]<<8 | num_L[num]);
        break;
    }
    }

};

void lcd_init(void)
{
        
        LCD_InitTypeDef LCD_InitStruct = {0};
        RCC_LSI_Enable();    // 启动LSI为LCD提供时钟
        __RCC_LCD_CLK_ENABLE();
        
        LCD_InitStruct.LCD_Bias = LCD_Bias_1_3;
        LCD_InitStruct.LCD_ClockSource = LCD_CLOCK_SOURCE_LSI;
        LCD_InitStruct.LCD_Duty = LCD_Duty_1_4;
        LCD_InitStruct.LCD_ScanFreq = LCD_SCAN_FREQ_256HZ;
        LCD_InitStruct.LCD_VoltageSource = LCD_VoltageSource_Internal;
        
        LCD_Init(&LCD_InitStruct);
        LCD_COMConfig(LCD_COM0 | LCD_COM1 | LCD_COM2 | LCD_COM3 , ENABLE);
        LCD_SEG0to23Config(LCD_SEG0|LCD_SEG1|LCD_SEG2|LCD_SEG3|LCD_SEG4|LCD_SEG5|LCD_SEG6|LCD_SEG7|LCD_SEG8|LCD_SEG9|LCD_SEG10|LCD_SEG13|LCD_SEG14|LCD_SEG15|LCD_SEG16|LCD_SEG17, ENABLE);
   
        LCD_Cmd(ENABLE);
        LCD_ContrastConfig(LCD_Contrast_Level_6);
        LCD_DriveVoltageConfig(LCD_INRS_LEVEL_0);
        
}

void lcd_clear(void)
{
        CW_LCD->RAM[0] =0;
        CW_LCD->RAM[1] =0;
        CW_LCD->RAM[2] =0;
        CW_LCD->RAM[3] =0;
        CW_LCD->RAM[4] =0;
}

主程序代码:
/******************************************************************************/

#include "main.h"
#include "log.h"
void show_weight(uint32_t weight);

int32_t main(void)
{
        lcd_init();
        Init_HX711pin();
        LogInit();
        InitTick(SystemCoreClock);
        Get_Maopi();
        SysTickDelay(2000);
        Get_Maopi();                                //重新获取毛皮重量
    CW_SYSCTRL->AHBEN_f.GPIOA = 1U;    //Open GPIOA Clk

    CW_GPIOA->ANALOG_f.PIN0 = 0U;      //Digital
    CW_GPIOA->BRR_f.BRR0 = 1U;         //Reset PA00
    CW_GPIOA->DIR_f.PIN0 = 0U;         //Output

                printf("start...\r\n");
    while(1)
    {
                        Get_Weight();

                        printf("净重量 = %d g\r\n",Weight_Shiwu); //打印
                        show_weight(Weight_Shiwu);
                        SysTickDelay(1000);
      CW_GPIOA->TOG = bv0;

    }

}

void show_weight(uint32_t weight)
{
        lcd_clear();
        if(weight>=10000)
        {
                lcd_show_string(4,weight/10000);
                lcd_show_string(3,weight%10000/1000);
                lcd_show_string(2,weight%1000/100);
                lcd_show_string(1,weight%100/10);
                lcd_show_string(0,weight%10);
        }
        else if(weight>=1000)
        {
                lcd_show_string(3,weight/1000);
                lcd_show_string(2,weight%1000/100);
                lcd_show_string(1,weight%100/10);
                lcd_show_string(0,weight%10);
        }
        else if(weight>=100)
        {
                lcd_show_string(2,weight/100);
                lcd_show_string(1,weight%100/10);
                lcd_show_string(0,weight%10);               
        }
        else if(weight>=10)
        {
                lcd_show_string(1,weight/10);
                lcd_show_string(0,weight%10);               
        }
        else{
                lcd_show_string(0,weight%10);
        }
        
}
/******************************************************************************
* EOF (not truncated)
******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  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 */

【调试】
由于不同的传感器,不同的温度,传感器的AD转换需要较调,我这里采集了100克的法码进行了设调,即修改GapValue的值。
【工程效果】:



使用特权

评论回复
沙发
chenjun89| | 2023-8-5 20:05 | 只看该作者
不错,设计简洁,朴实无华,哈哈。

使用特权

评论回复
板凳
weifeng90| | 2023-8-6 09:02 | 只看该作者
0.01%的精度,怎么校准?

使用特权

评论回复
地板
lulugl|  楼主 | 2023-8-6 11:19 | 只看该作者
weifeng90 发表于 2023-8-6 09:02
0.01%的精度,怎么校准?

用法码较了一下,要想非常精准,还需要测量温度来较准。

使用特权

评论回复
5
sdlls| | 2023-8-7 16:18 | 只看该作者
这个电子秤时怎么校验的?              

使用特权

评论回复
6
macpherson| | 2023-8-7 16:32 | 只看该作者
注意电源管理,使得电子秤具备低功耗和长续航能力。

使用特权

评论回复
7
nomomy| | 2023-8-7 16:56 | 只看该作者
使用CW32L052微控制器,它具有高性能和低功耗的特点,非常适合用于电子秤设计。

使用特权

评论回复
8
kmzuaz| | 2023-8-7 17:18 | 只看该作者
校准过程可能涉及使用已知重量进行比较和调整。

使用特权

评论回复
9
lulugl|  楼主 | 2023-8-7 17:30 | 只看该作者
macpherson 发表于 2023-8-7 16:32
注意电源管理,使得电子秤具备低功耗和长续航能力。

就是做个示例,如果做成产品,还有许多因素要考虑的。L052带了LCD控制器,做称还是非常合适的。

使用特权

评论回复
10
lulugl|  楼主 | 2023-8-7 17:31 | 只看该作者
kmzuaz 发表于 2023-8-7 17:18
校准过程可能涉及使用已知重量进行比较和调整。

真正的较准,要在指定的温度、湿度下面进行较准。没有这个专业设备。

使用特权

评论回复
11
sanfuzi| | 2023-8-7 17:40 | 只看该作者
单片机电子秤设计如何标定?               

使用特权

评论回复
12
lulugl|  楼主 | 2023-8-7 17:44 | 只看该作者
sanfuzi 发表于 2023-8-7 17:40
单片机电子秤设计如何标定?

用法码标定呀。要想准确,还得标定每个温度值的标定植,处理起来比较麻烦。因为压力传感是金属,所以不同的温度,要给出不同的较准值。

使用特权

评论回复
13
ccook11| | 2023-8-7 18:02 | 只看该作者
CW32L052是一款低功耗的ARM Cortex-M0+微控制器,适合用于电子秤等嵌入式系统的设计

使用特权

评论回复
14
phoenixwhite| | 2023-8-7 18:27 | 只看该作者
选择合适的传感器来测量重量 。然后需要使用单片机或微控制器来控制整个系统。

使用特权

评论回复
15
uytyu| | 2023-8-7 18:50 | 只看该作者
电子秤在设计 中为了减少误差,具体有哪些方**

使用特权

评论回复
16
fengm| | 2023-8-7 19:12 | 只看该作者
扭矩传感器设计一个电子秤               

使用特权

评论回复
17
mnynt121| | 2023-8-7 19:33 | 只看该作者
传感器如何选择?A/D如何选择?

使用特权

评论回复
18
loutin| | 2023-8-7 19:55 | 只看该作者
网上有资料可以参考的吗?              

使用特权

评论回复
19
biechedan| | 2023-8-7 20:18 | 只看该作者
使用ADC来将模拟信号转换为数字信号

使用特权

评论回复
20
saservice| | 2023-8-7 20:41 | 只看该作者
常见的选择包括压力传感器、应变片传感器

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

156

主题

744

帖子

10

粉丝