• 正文
  • 相关推荐
申请入驻 产业图谱

CW32L012多功能电子秤案例实现分享

06/20 08:17
256
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

前言:基于CW32L012的多功能电子秤系统是集称重,计价,标定,去皮,计件等功能于一体的系统,实现了事实上的电子秤全功能。

一、实物展示:

二、HX711模块介绍

本称重系统使用HX711芯片,HX711是海芯专利的24位高精度AD芯片,专为电子秤设计。它集成稳压、时钟等外围电路,集成度高、速度快、抗干扰强,能降成本、提稳定性。芯片对接单片机简单,靠引脚控制无需寄存器配置;支持两路输入,A通道增益可调,适配称重信号,B通道固定增益用于系统检测。自带稳压电源时钟电路,还具备上电自复位,外围极简,使用便捷。下附实物图片及电路图

模块特性:

1.两路可选择差分输入。

2.片内低噪声可编程放大器,可选增益为 32,64 和 128 • 片内稳压电路可3.直接向外部传感器和芯片内 A/D 转换器提供电源。

4.片内时钟振荡器无需任何外接器件,必要时 也可使用外接晶振或时钟上电自动复位电路

5.简单的数字控制和串口通讯:所有控制由管 脚输入,芯片内寄存器无需编程。

6.可选择 10Hz 或 80Hz 的输出数据速率。

7.同步抑制 50Hz 和 60Hz 的电源干扰。

8.耗电量(含稳压电源电路): 典型工作电流:< 1.6mA, 断电电流:< 1µA。

9.工作电压范围:2.6 ~ 5.5V;工作温度范围:-40 ~ +85℃。

10.16 管脚的 SOP-16 封装

该模块实现称重的逻辑:

1.压力转电信号称重传感器受压力形变,输出微弱差分电压信号。2.信号放大信号送入HX711,经内部可编程放大器放大。3.AD转换24位模数转换器将模拟电压转为数字量。4.数据传输HX711通过IO引脚把数字值发给主控MCU。5.软件换算单片机读取数值,做去皮、校准、公式运算,最终算出重量并显示。

三、软件讲解:

上面讲解为称重系统核心部分。其他部分将在下面keil工程中具体呈现,其中不乏含有物理键盘,串口通讯,TFT彩屏以及main文件的核心部分。

HX711.c和h

#include "HX711.h"#include "delay.h"#include "global.h"#include "cw32l012_gpio.h"#include "cw32l012_sysctrl.h"#include "stdlib.h"u32 HX711_Buffer;u32 Weight_Maopi;s32 Weight_Shiwu;u8  Flag_Error = 0;u32 Maopi_flag;/* HX711 专用延时,不依赖 delay_us,纯循环消耗时间 */static void hx711_delay(void){    volatile unsigned int i;    for (i = 0; i < 20; i++) __nop();}void Init_HX711pin(void){    GPIO_InitTypeDef GPIO_InitStructure = {0};    __SYSCTRL_GPIOB_CLK_ENABLE();    /* PB8 — SCK 推挽输出 */    GPIO_InitStructure.IT   = GPIO_IT_NONE;    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;    GPIO_InitStructure.Pins = GPIO_PIN_8;    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);    /* PB9 — DOUT 上拉输入 */    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;    GPIO_InitStructure.Pins = GPIO_PIN_9;    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);    HX711_SCK(0);}u32 HX711_Read(void){    unsigned long count = 0;    unsigned char i;    unsigned int  timeout = 0;    HX711_SCK(0);    hx711_delay();    /* 等待 DOUT 变低,加超时保护 */    while (HX711_DOUT)    {        timeout++;        hx711_delay();        if (timeout > 50000)        {            Flag_Error = 1;            return Weight_Maopi;        }    }    Flag_Error = 0;    for (i = 0; i < 24; i++)    {        HX711_SCK(1);        hx711_delay();        count = count << 1;        if (HX711_DOUT) count++;        HX711_SCK(0);        hx711_delay();    }    /* 第25个脉冲 */    HX711_SCK(1);    count = count ^ 0x800000;    hx711_delay();    HX711_SCK(0);    hx711_delay();    return count;}void Get_Maopi(void){    u32 val = HX711_Read();    if (Flag_Error == 0)        Weight_Maopi = val;}u32 tempweight;void Get_Weight(void){    static s32 last_weight = 0;    unsigned int i;    long max = 0;    s32 new_weight;    /* 取2次平均,*/    for (i = 0; i < 2; i++)    {        HX711_Buffer = HX711_Read();        max += HX711_Buffer;    }    max /= 2;    HX711_Buffer = (u32)max;    if (HX711_Buffer > Weight_Maopi)    {        new_weight = (s32)(HX711_Buffer - Weight_Maopi);        new_weight = (s32)((float)new_weight / scalar);        if (new_weight < 0) new_weight = 0;    }    else    {        new_weight = 0;    }    /* 死区滤波:变化小于 2g 不更新,消除抖动 */    if (new_weight == 0 || abs(new_weight - last_weight) >= 2)    {        Weight_Shiwu = new_weight;        last_weight  = new_weight;    }}#ifndef __HX711_H#define __HX711_H#include "cw32l012.h"#include "cw32l012_gpio.h"#include "Lcd_Driver.h" /* SCK — PB8,DOUT — PB9 */#define HX711_SCK(x)  GPIO_WritePin(CW_GPIOB, GPIO_PIN_8, (x) ? GPIO_Pin_SET : GPIO_Pin_RESET)#define HX711_DOUT    GPIO_ReadPin(CW_GPIOB, GPIO_PIN_9)extern void Init_HX711pin(void);extern u32  HX711_Read(void);extern void Get_Maopi(void);extern void Get_Weight(void);extern u32  HX711_Buffer;extern u32  Weight_Maopi;extern s32  Weight_Shiwu;extern u8   Flag_Error;extern u32  Maopi_flag;#endif

usart2.c和h

 

#include "usart2.h"#include <string.h>#include "cw32l012.h"#include "cw32l012_gpio.h"#include "cw32l012_uart.h"#include "cw32l012_sysctrl.h"#include "global.h"#include "delay.h"#include "Lcd_Driver.h"extern float        Single_Weight;extern int          goods_count;extern unsigned int Weight_Maopi;extern unsigned int Maopi_flag;extern int          Weight_Shiwu;extern int          total;extern int          price;extern int          ax;extern float        ex;extern short int    Temp_num;extern char         txt1[];extern void         Key_Character(uint16_t uKey);extern void         Gui_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, char *str);extern u32          HX711_Buffer;extern float        scalar;extern unsigned int SaveFlag;/* 标志位,中断里只设标志,主循环里执行实际操作 */unsigned char tare_flag  = 0;unsigned char calib_flag = 0;/* ========== 业务函数 ========== */void On_App_Calibrate(void){    calib_flag = 1;  /* 只设标志,主循环里处理 */}void On_App_NumInput(uint8_t num){    char temp_txt[10];    if (price < 1000)        price = price * 10 + num;    sprintf(temp_txt, "%d   ", price);    Gui_DrawFont_GBK16(60, 47, YELLOW, BLACK, temp_txt);}void On_App_SetCount(void){    if (Weight_Shiwu > 1)    {        Single_Weight = (float)Weight_Shiwu;        Gui_DrawFont_GBK16(10, 110, RED, BLACK, "SAMPLE OK! ");    }    else    {        Gui_DrawFont_GBK16(10, 110, RED, BLACK, "NO GOODS!  ");    }}void On_App_SetConfirm(void){    total = (u32)(price * Weight_Shiwu);    sprintf(txt1, "%d   ", total);    Gui_DrawFont_GBK16(60, 69, YELLOW, BLACK, txt1);}void On_App_SetTare(void){    tare_flag = 1;  /* 只设标志,主循环里处理 */}void On_App_SetClear(void){    Weight_Maopi  = Maopi_flag;    total = 0; price = 0; Weight_Shiwu = 0;    goods_count = 0; Single_Weight = 0.0f;    memset(txt1, 0, 50);    Gui_DrawFont_GBK16(60,  69, YELLOW, BLACK, "        ");    Gui_DrawFont_GBK16(60,  47, YELLOW, BLACK, "        ");    Gui_DrawFont_GBK16(10, 110, BLACK,  BLACK, "            ");}void On_App_SetPoint(void) {}void On_App_SetAdd(void)   {}void On_App_SetPay(void)   {}/* ========== 协议解析 ========== */static uint8_t Calculate_FCS(uint8_t *pkt, uint8_t len){    uint8_t calculatedXOR = pkt[0];    int i;    for (i = 1; i < len; i++)        calculatedXOR ^= pkt[i];    return calculatedXOR;}void Protocol_ParseCommand(uint8_t *rx_buf, uint8_t rx_len){    uint8_t cmd, code, length;    if (rx_buf[0] != 0x55 || rx_buf[rx_len - 1] != 0x56) return;    cmd    = rx_buf[1];    code   = rx_buf[2];    length = rx_buf[3];    if (rx_len != (length + 6)) return;    if (Calculate_FCS(&rx_buf[1], 3 + length) != rx_buf[4 + length]) return;    if (cmd == 0x03)    {        switch (code)        {            case 0x01: On_App_SetTare();    break;            case 0x02: On_App_SetClear();   break;            case 0x03: On_App_SetCount();   break;            case 0x04: On_App_SetConfirm(); break;            case 0x05: On_App_NumInput(0);  break;            case 0x06: On_App_NumInput(1);  break;            case 0x07: On_App_NumInput(2);  break;            case 0x08: On_App_NumInput(3);  break;            case 0x09: On_App_NumInput(4);  break;            case 0x0A: On_App_NumInput(5);  break;            case 0x0B: On_App_NumInput(6);  break;            case 0x0C: On_App_NumInput(7);  break;            case 0x0D: On_App_NumInput(8);  break;            case 0x0E: On_App_NumInput(9);  break;            case 0x0F: On_App_Calibrate();  break;            case 0x10: On_App_SetAdd();     break;            case 0x11: On_App_SetPay();     break;            default: break;        }    }}/* ========== 串口2中断 ========== */#define RX_BUF_SIZE  32uint8_t g_rx_buffer[RX_BUF_SIZE];uint8_t g_rx_index = 0;void UART2_IRQHandler(void){    static uint8_t rx_state = 0;    static uint8_t data_len = 0;    uint8_t rx_byte;    if (UART_GetITStatus(CW_UART2, UART_IT_RC) != RESET)    {        UART_ClearITPendingBit(CW_UART2, UART_IT_RC);        rx_byte = UART_ReceiveData(CW_UART2);        switch (rx_state)        {            case 0:                if (rx_byte == 0x55)                {                    g_rx_index = 0;                    g_rx_buffer[g_rx_index++] = rx_byte;                    rx_state = 1;                }                break;            case 1:                g_rx_buffer[g_rx_index++] = rx_byte;                rx_state = 2;                break;            case 2:                g_rx_buffer[g_rx_index++] = rx_byte;                rx_state = 3;                break;            case 3:                g_rx_buffer[g_rx_index++] = rx_byte;                data_len = rx_byte;                if (data_len < (RX_BUF_SIZE - 6))                    rx_state = (data_len == 0) ? 5 : 4;                else                    rx_state = 0;                break;            case 4:                g_rx_buffer[g_rx_index++] = rx_byte;                data_len--;                if (data_len == 0) rx_state = 5;                break;            case 5:                g_rx_buffer[g_rx_index++] = rx_byte;                rx_state = 6;                break;            case 6:                g_rx_buffer[g_rx_index++] = rx_byte;                if (rx_byte == 0x56)                    Protocol_ParseCommand(g_rx_buffer, g_rx_index);                rx_state = 0;                break;            default:                rx_state = 0;                break;        }        if (g_rx_index >= RX_BUF_SIZE)        {            rx_state   = 0;            g_rx_index = 0;        }    }}/* ========== 串口2初始化 ========== */void Usart2_Init(u32 USART_BAUDRATE){    GPIO_InitTypeDef GPIO_InitStructure = {0};    UART_InitTypeDef UART_InitStruct    = {0};    __SYSCTRL_GPIOA_CLK_ENABLE();    __SYSCTRL_GPIOC_CLK_ENABLE();    __SYSCTRL_UART2_CLK_ENABLE();    PA02_AFx_UART2TXD();    PA03_AFx_UART2RXD();    GPIO_InitStructure.Pins = GPIO_PIN_2;    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);    GPIO_InitStructure.Pins = GPIO_PIN_3;    GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);    UART_InitStruct.UART_BaudRate  = USART_BAUDRATE;    UART_InitStruct.UART_Source    = UART_Source_PCLK;    UART_InitStruct.UART_UclkFreq  = 96000000;    UART_InitStruct.UART_Mode      = UART_Mode_Rx | UART_Mode_Tx;    UART_Init(CW_UART2, &UART_InitStruct);    UART_ITConfig(CW_UART2, UART_IT_RC, ENABLE);    UART_ClearITPendingBit(CW_UART2, UART_IT_RC);    NVIC_SetPriority(UART2_IRQn, 1);    NVIC_EnableIRQ(UART2_IRQn);}/* ========== 发送函数 ========== */void Usart_SendByte(UART_TypeDef *pUARTx, uint8_t ch){    UART_SendData(pUARTx, ch);    while (UART_GetFlagStatus(pUARTx, UART_FLAG_TXE) == RESET);}void Usart_SendString(UART_TypeDef *pUARTx, char *str){    unsigned int k = 0;    do    {        Usart_SendByte(pUARTx, *(str + k));        k++;    } while (*(str + k) != '');    while (UART_GetFlagStatus(pUARTx, UART_FLAG_TXE) == RESET);}void Usart_SendHalfWord(UART_TypeDef *pUARTx, uint16_t ch){    Usart_SendByte(pUARTx, (ch & 0xFF00) >> 8);    Usart_SendByte(pUARTx,  ch & 0x00FF);}#ifndef __USART2_H#define __USART2_H#include "cw32l012.h"#ifndef u32#define u32 unsigned int#endif#ifndef u16#define u16 unsigned short#endif#ifndef uchar#define uchar unsigned char#endif/* 标志位,供 main.c 主循环使用 */extern unsigned char tare_flag;extern unsigned char calib_flag;/* 业务函数声明 */void On_App_Calibrate(void);void On_App_NumInput(uint8_t num);void On_App_SetCount(void);void On_App_SetConfirm(void);void On_App_SetTare(void);void On_App_SetClear(void);void On_App_SetPoint(void);void On_App_SetAdd(void);void On_App_SetPay(void);void Protocol_ParseCommand(uint8_t *rx_buf, uint8_t rx_len);/* 串口底层函数声明 */void Usart2_Init(u32 USART_BAUDRATE);void Usart_SendByte(UART_TypeDef *pUARTx, uint8_t ch);void Usart_SendString(UART_TypeDef *pUARTx, char *str);void Usart_SendHalfWord(UART_TypeDef *pUARTx, uint16_t ch);#endif

四、总结与建议:

整个电子秤系统涉及多个模块包括HX711称重模块,TFT彩屏,物理键盘,蓝牙模块,CW32L012主控板。

在进行称重时应先去皮再放重物,如不准则进行标定,标定后重新放重物进行称重。

进行称重时,重物应尽量放在电子秤的中心,如不放中心可能会存在微小误差。

按键要做消抖处理,否则可能会不准确。

称重要数据滤波,合理设置数值范围与存储位数,避免跳数、溢出。

串口要设置正确的波特率否则会造成通信不成功。


扫码加入QQ群3群| 610403240

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

以开放、共享、互助为理念,致力于构建武汉芯源半导体CW32系列MCU生态社区。无论是嵌入式MCU小自还是想要攻破技术难题的工程师,亦或是需求解决方案的产品经理都可在CW32生态社区汲取营养、共同成长。