历史上的今天
返回首页

历史上的今天

今天是:2024年10月12日(星期六)

正在发生

2020年10月12日 | 自制BMS监控仪通过485通讯读BMS信息并显示在LCD2004上

2020-10-12 来源:51hei

公司是做锂电池管理系统的,主要是通信用16串锂电池用的保护板(BMS),产品有485接口,可以上传各种测量和告警信息。最近开始学习单片机,自己动手做了一个BMS监控仪,通过485与自家的BMS通讯获取状态信息并显示在LCD2004上。
程序也是自己弄了好久才排除各种bug,现在具备了基本状态信息显示、菜单、16串单体电压显示、各温度显示、BMS状态显示、基本告警信息显示。
这个小产品使用STC89C54RD+,MAX485芯,使用5V升压锂电池供电,在外壳上留出了USB充电接口。
电路原图是自己搞了一个,然后同事帮我画的PCB。制作比较废劲,尤其是壳子不好切割,还把手割伤了。。。
因为工作比较忙,从头到尾断断续续搞了一个来月终于算是完成了,和大家分享一下。

已附上原理图和单片机程序。因自己初学,程序有很多不足,比如没有按模块化编写、逻辑较乱等,希望大家帮忙指点。

制作出来的实物图如下:
     

电路原理图如下:

单片机源程序如下:

#include "STC89C54.h"

#define uint unsigned int

#define uchar unsigned char


uchar code welcome1[]="BMS Monitor";

uchar code welcome2[]="RichPower";

uchar code waiting[]="CONNECTING...";

uchar code menu_table1[]="CELL VOLTAGE"; //12个字符

uchar code menu_table2[]="TEMPERATURE";  //11个字符

uchar code menu_table3[]="BMS STATUS";        //10个字符

uchar code menu_table4[]="ALARM INFO"; //10个字符

uchar code BMSINFO1[20]={0x7E,0x32,0x36,0x30,0x30,0x34,0x36,0x46,0x32,0x45,0x30,0x30,0x32,0x30,0x31,0x46,0x44,0x31,0x45,0x0D};         //询遥测的命令报文

uchar code BMSINFO2[20]={0x7E,0x32,0x36,0x30,0x30,0x34,0x36,0x46,0x34,0x45,0x30,0x30,0x32,0x30,0x31,0x46,0x44,0x31,0x43,0x0D};  //询遥信命令报文

uchar buffer[145]={0};          //用于缓存遥测报文

sbit lcdrs=P2^5;        //指令和数据寄存器选择,高电平时为数据,低电平选择命令

sbit lcdrw=P2^6;        //读写选择,高电平为读,低电平为写

sbit lcden=P2^7;    //使能

sbit lcdbg=P2^4;        //背光,0为开

sbit beep=P2^0;                //蜂鸣器,0为开

sbit key1=P1^0;                //菜单或确认

sbit key2=P1^1;                //上一项

sbit key3=P1^2;                //下一项

sbit key4=P1^3;                //返回或背光开关

bit data datareceived_flag=0,displayclear=1;           //datareceived_flag为遥测报文是否接收完的标志位,current_bit为电流值符号标志位

bit data current_bit,celltemp_unit,envtemp_unit,mostemp_unit;

uchar data num;

uchar data i=0,watchdog=0,end_position;

uint single_max,single_min,totalvoltage,current,totalcap,remaincap;

uint data remaincap2;               

uchar digit0,digit1,digit2,digit3,digit4;                                   //LCD显示数字的万千百十个位

uchar cellnumber,cellnumber_offset,address_offset;                 //串数,串数差,地址偏移量

uchar cappercentage;                                                                         //SOC

uint singlevoltage[15];                                                   //单体电芯电压

uint temperature[5];                                                           //4个电芯温度和环境温度及功率温度

uchar display_mode=0,menu_position=1,singlevoltage_page=1;                         //显示模式



void delayms(uint z)         //延时子程序

{

        uint x,y;

        for(x=z;x>0;x--)

                for(y=110;y>0;y--);

}



void write_com(uchar com)           //LCD1602写命令函数

{

        lcdrs=0;                 //rs低电平为写命令

        P0=com;                        

        delayms(4);

        lcden=1;                 //EN先置高电平

        delayms(4);

        lcden=0;                 //短暂延时后EN置低电平

}

void write_dat(uchar dat)           //LCD1602写数据函数

{

        lcdrs=1;                 //rs高电平为写数据

        P0=dat;

        delayms(4);

        lcden=1;

        delayms(4);

        lcden=0;

}


void UsartInit()           //串口初始化

{

        SCON=0X50;                        //设置为工作方式1

        TMOD=0X20;                        //设置计数器工作方式2

        PCON=0X80;                        //波特率加倍

        TH1=0XFA;                                //计数器初始值设置,注意11.0592Mhz波特率是9600的

        TL1=0XFA;

        ES=1;                                                //打开接收中断

        EA=1;                                                //打开总中断

        TR1=1;                                        //打开计数器

}


void init()                                //LCD初始化及开机界面

{

        lcdrw=0;

        lcden=0;

        P0=0;

        write_com(0x38);

        write_com(0x0f);   //初始化,开显示,开光标,开光标闪烁

        write_com(0x06);   //初始化,读写一个字符后地址指针自动加1

        write_com(0x01);   //清屏

//        write_com(0x80);   //数据地址指针从0开始

        lcdbg=0;                   //开背光

        write_com(0x0C);        //关光标

/**********************欢迎界面**************************/

        write_com(0x80+0x44);  //第2行第5个字符

        for(num=0;num<11;num++)

        write_dat(welcome1[num]);

        write_com(0x94+0x05);         //第3行第6个字符

        for(num=0;num<9;num++)

        write_dat(welcome2[num]);

        delayms(1000);

        beep=0;

        delayms(60);

        beep=1;

/********************************************************/

}


/********************************************************************************

计算报文缓存中的一个字节

********************************************************************************/

uchar buffer_byte_process(uchar buffer_address)

{

        uchar byte_value;

        if(buffer[buffer_address]<=0x39)

                buffer[buffer_address]=buffer[buffer_address]-0x30;        //若为0~9的字符,减0x30即为数值

        else

                buffer[buffer_address]=buffer[buffer_address]-0x37;        //若为大于9即为A~F的字符,减0x37即为数值

        if(buffer[buffer_address+1]<=0x39)

                buffer[buffer_address+1]=buffer[buffer_address+1]-0x30;

        else

                buffer[buffer_address+1]=buffer[buffer_address+1]-0x37;

        byte_value=(buffer[buffer_address]<<4)|buffer[buffer_address+1];               

        return byte_value;

}


/********************************************************************************

计算报文缓存中的一个字

********************************************************************************/

uint buffer_word_process(uchar buffer_address)

{

        uint word_value;

        if(buffer[buffer_address]<=0x39)

                buffer[buffer_address]=buffer[buffer_address]-0x30;        //若为0~9的字符,减0x30即为数值

        else

                buffer[buffer_address]=buffer[buffer_address]-0x37;        //若为大于9即为A~F的字符,减0x37即为数值

        if(buffer[buffer_address+1]<=0x39)

                buffer[buffer_address+1]=buffer[buffer_address+1]-0x30;

        else

                buffer[buffer_address+1]=buffer[buffer_address+1]-0x37;

        if(buffer[buffer_address+2]<=0x39)

                buffer[buffer_address+2]=buffer[buffer_address+2]-0x30;        //若为0~9的字符,减0x30即为数值

        else

                buffer[buffer_address+2]=buffer[buffer_address+2]-0x37;        //若为大于9即为A~F的字符,减0x37即为数值

推荐阅读

史海拾趣

FOCI Fiber Optic Communications Inc公司的发展小趣事

FOCI Fiber Optic Communications Inc.公司发展的五个故事

故事一:成立与初创期

FOCI Fiber Optic Communications Inc.(以下简称FOCI)成立于1995年,由台湾工业技术研究院(工研院)的核心团队创立。这家公司自诞生之初就专注于光纤互连技术的发展,致力于设计、制造和销售高性能的光纤组件和集成模块。初创时期,FOCI凭借其对光纤技术的深刻理解和市场需求的敏锐洞察,逐步在市场上站稳脚跟,成为光纤通信领域的一股新兴力量。

故事二:技术创新与突破

FOCI在发展过程中,始终将技术创新视为企业发展的核心驱动力。公司不断投入研发资源,在光纤耦合器、PLC分配器、薄膜粗波分复用/密集波分复用以及多光纤电缆组装模块等领域取得了多项技术突破。这些技术创新不仅提升了产品的性能和质量,还大幅降低了生产成本,使得FOCI的产品在市场上更具竞争力。

故事三:与奇景光电的战略合作

2024年,半导体解决方案无晶圆厂巨头奇景光电(Himax Technologies)宣布向FOCI投入5.22亿新台币(折合约为1610万美元)的资金。这次投资不仅是两家公司财务合作的结果,更是双方在技术融合与应用拓展上迈出的重要一步。根据合作协议,FOCI的共封装光学器件(CPO)与奇景光电的晶圆级光学器件(WLO)将被整合到多芯片模块中,这些模块将广泛应用于高性能计算、云服务器、人工智能等多个领域。

故事四:全球化布局与市场拓展

随着全球光纤通信市场的快速发展,FOCI积极实施全球化战略,不断拓展国际市场。公司通过参加国际展会、建立海外销售网络等方式,将高性能的光纤组件和集成模块带到了世界各地。特别是在光纤到户(FTTH)和云计算领域,FOCI的产品因其高效、低成本的特性而广受欢迎,成功在全球市场占据了一席之地。

故事五:子公司设立与多元化发展

为了进一步拓展业务领域和市场份额,FOCI在国内设立了多家子公司,如中山上诠通信科技有限公司等。这些子公司不仅继承了FOCI在光纤通信领域的深厚底蕴和技术优势,还根据当地市场需求进行了产品和服务的本地化调整。同时,FOCI还积极探索多元化发展路径,涉足光纤高速数据传输技术开发设计、研发和咨询等多个领域,为公司未来的持续发展奠定了坚实基础。

创都(CAX)公司的发展小趣事

在电子行业的浪潮中,创都(CAX)公司凭借其卓越的技术创新能力,逐渐崭露头角。公司创始人李先生是一位热衷于新技术的电子工程师,他带领着一支由业内顶尖人才组成的研发团队,不断挑战技术极限。在一次偶然的机会中,他们成功研发出了一款具有革命性意义的高效能芯片,这款芯片不仅性能卓越,而且成本大幅降低,迅速在市场中获得了广泛认可。随着这款芯片的成功推出,创都公司的知名度迅速提升,订单量激增,公司也借此机会逐步扩大了生产规模和市场占有率。

CSR plc(剑桥硅晶无线电)公司的发展小趣事

随着技术的不断进步和市场需求的日益多样化,CSR plc意识到单一的业务领域已无法满足公司的长远发展。于是,公司开始寻求多元化的发展道路。2007年,CSR plc成功收购了Nordnav Technologies和Cambridge Positioning Systems,开始进军GPS市场。这一战略转型不仅让公司的业务范围得到了极大的拓展,也使其在GPS领域取得了显著的成就。

BETA Transformer Technology Corp公司的发展小趣事

随着全球环保意识的不断提高,BETA Transformer Technology Corp公司积极响应国家绿色发展的号召,将环保理念贯穿于产品研发、生产和销售的全过程。公司推出了一系列节能环保的变压器产品,深受客户好评。同时,BETA公司还加强了对生产废弃物的处理和回收利用,实现了资源的循环利用和减少环境污染。这些举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实基础。

微芯(CMOSIC)公司的发展小趣事

为了进一步提升研发实力和市场竞争力,微芯生物开始了并购之路。他们先后收购了多家在生物医药领域具有优势的企业,包括专注于生物制品生产和销售的企业、创新药物研发企业以及提供全方位生物医药研发生产外包服务的企业等。通过并购整合,微芯生物不仅增强了自身的研发实力和市场占有率,还进一步完善了公司的产业链和战略布局。

BUSSMANN公司的发展小趣事

1992年,Bussmann开始了第一款芯片保险丝的开发工作。这款保险丝将可熔性材料沉降到陶瓷基底上,大小只有3mm*1.5mm,可以通过自动装配机安装到印刷电路板上。这一创新不仅大大提高了熔断器的性能和可靠性,还降低了生产成本,为电子行业的发展注入了新的活力。

问答坊 | AI 解惑

锁相环频率捕捉过程的计算机辅助设计

[摘要〕在对锁相环频率捕捉过程进行数学分析的基础之上,给出了用计算机模拟锁相环频率捕捉过程的基本方法和计算程序。文中对一个具体例子做了模拟,模拟结果与理论分析完全吻合。…

查看全部问答>

实用的4~20mA输入/0~5V输出的I/V转换电路

最简单的4-20mA输入/5V输出的I/V转换电路 在与电流输出的传感器接口的时候,为了把传感器(变送器)输出的1-10mA或者4-20mA电流信号转换成为电压信号,往往都会在后级电路的最前端配置一个I/V转换电路,图1就是这种电路最简单的应用示意图。 ...…

查看全部问答>

利用SOPC Builder生成系统时的问题

利用SOPC Builder生成系统时,需要添加一个SSRAM模块进去,但是QUARTUS II 7.2版本的SSRAM型号是CY7C1380C,而我的板子上面用到的是IS61LPS12836A_200TQLI,我查看了二者的datasheet,发现二者引脚完全一致,以及真值表也一样,请问能否用CY7C1380C ...…

查看全部问答>

wince起来之后,点一下就死机了,帮忙分析一下原因

这是串口打印的信息 RomBOOT>By www.mcuzone.com ...Master Clock is ???????? Hz ?FMD_DirectRead lasted 0 ms for 0x46 bytes (timer granularity is 400) Press [ENTER] to launch image stored in flash or [SPACE] to cancel. Initiating ...…

查看全部问答>

关于放大类题目讨论~

本帖最后由 paulhyde 于 2014-9-15 09:00 编辑 首先~那个电源的话~3.6v~是通过220v还是有提供直流电源转换过去?  …

查看全部问答>

AVR单片机怎么用AD算传感器波形的值

大家有谁知道这个波形怎么算吗,就是怎么算出一个标准的值!非常感谢!…

查看全部问答>

用CCS打开TivaWare工程,变异出错(error #10234-D: unresolved symbols remain)...

用CCS打开官方提供的TivaWare里面的工程,添加头文件添加了#include “utils/uartstdio.h\",而且编译器也能找到Uartprintf()函数,但是主程序中调用它时,就会报错 undefined                f ...…

查看全部问答>

关于2个红外传感器被触发的先后顺序的问题

两个红外传感器被触发的先后顺序怎么来判断?哪位大神来帮帮我啊~ …

查看全部问答>

新人求教 如何实现PC通过串口控制接收端的IO……

想实现一个PC通过串口发送数据到发送端,然后通过无线控制接收端的IO的程序……求指导 …

查看全部问答>

团购开发板STM32Nucleo心得之开发工具

Cortex-M0开发板种类多,但从目前看STM32Nucleo的开发平台是最好的。 有些厂家的开发平台是自己独立开发的,有些不支持开源GCC.但是STM32Nucleo的平台丰富得难以选择。 1. 支持第三方开发平台。如IAR,Keil.而且是得到开发厂家的支持的,最新版的 ...…

查看全部问答>