公司是做锂电池管理系统的,主要是通信用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即为数值
上一篇:单片机非接触式智能测温系统程序
下一篇:单片机动态数码管显示DS18B20测温显示程序
推荐阅读
史海拾趣
酷宅科技在创业之初就意识到了海外市场的重要性。因此,公司将自己的服务部署在亚马逊的AWS云上,并针对AWS Alexa for Business、Google Home等主流智能音箱平台进行了深度优化。这一战略使酷宅科技的产品能够更好地适应海外市场的需求,提高其品牌在国际市场的竞争力。同时,酷宅还积极参加国际展览和论坛,与全球合作伙伴建立广泛的联系,进一步推动其国际化战略的实施。
在国内市场取得一定成绩后,Fairview Microwave开始将目光投向国际市场。他们积极参加国际电子展会和技术交流活动,与全球各地的客户建立联系。同时,公司还积极开拓海外市场,通过设立分支机构和代理商等方式,将产品销售到全球各地。这些举措不仅为公司带来了更多的商机,也进一步提升了Fairview Microwave的品牌知名度和影响力。
随着技术的不断进步和市场的变化,EETools意识到必须不断创新才能保持竞争力。公司投入大量研发资源,对嵌入式开发工具进行技术升级和产品优化。经过数年的努力,EETools成功推出了一系列具有领先技术的嵌入式开发工具,如高性能的芯片编程器、智能调试器等。这些产品不仅提高了客户的工作效率,还降低了成本,赢得了市场的广泛认可。
进入21世纪后,随着数码技术的迅速崛起,传统摄影市场遭受了巨大的冲击。面对这一挑战,伊士曼柯达公司开始尝试向数码领域转型。然而,由于公司在数码技术方面的积累相对较少,转型过程并不顺利。尽管如此,柯达仍然坚持创新,不断推出新的数码产品,以应对市场的变化。同时,公司还加强了与数码技术公司的合作,共同研发新产品,以提高市场竞争力。
为了进一步增强市场影响力,Dialog Semiconductor通过一系列的收购策略来扩大其业务范围。例如,在2020年,公司收购了Adesto Technologies,这是一家专注于非易失性存储器(NVM)解决方案的公司。此次收购为Dialog Semiconductor带来了近5,000家新客户,并补充了其在无线连接产品之外的有线连接解决方案。同年,Dialog Semiconductor还收购了另一家公司,获得了强大的核心IC产品组合和经验丰富的工程师团队,进一步巩固了其在IoT市场的地位。
随着全球电子市场的不断扩大,CW Industries也积极拓展其国际业务。公司通过参加各种国际电子展会和交流活动,与全球各地的客户和合作伙伴建立了广泛的联系。这不仅为公司带来了更多的商机,还使得CW Industries能够及时了解国际市场的最新动态和技术趋势。通过这些国际交流活动,CW Industries不断提升其品牌影响力和市场竞争力。
ISE综合错误:Failed to synthesize logic for signal 最近用ISE写个频率计的verilog程序 , 下面这个报错弄了很久没发现错在哪,在quartus里综合能通过,但在ISE里综合就不行,能哪位大虾能指点一二吗?不胜感激!`timescale 1ns / 1psmodule plj(clk,clk_test,sw0,sw1,rst,out_wei,ou ...… 查看全部问答∨ |
|
这两天用STM32F103ZCT6开发碰到怪事了:我用KEIL + JLINK II进行开发,在编译好以,下载到我的片上,用反汇编看烧写下去的代码,会有一段区域是全1,也就是代码没有烧写成功,不知为什么1!!开始怀疑是这个扇区坏了,但用别一 ...… 查看全部问答∨ |
|
#include <MSP430x14x.h> void main (void) { int i; int array[]={1,2,3,4,5}; int l=1; while(1) { switch (l) { case 1:i=array[l];break; case 2:i=array[l];break; ...… 查看全部问答∨ |
|
Flexibility has been one of the advantages Series 2600instruments provided. Such flexibility was due in part to theirindependence from a rigid trigger model, which was common to SCPI-based instrumentation. However, using a tri ...… 查看全部问答∨ |
安防英才网讯10月31日,由广东省公共安全技术防范协会与深圳市安全防范行业协会主办,广东省公安厅安全技术防范办公室协办的“2012年中国广东国际社会公共安全产品博览会”(下称“广东安博会”)新闻发布会在深圳国际会展中心召开。会议通报了2012 ...… 查看全部问答∨ |