⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yh_t3_new.c

📁 电子秤源程序。去年的心血啊!c语言编写的51单片机程序。
💻 C
📖 第 1 页 / 共 5 页
字号:
/********************************
说明:
1.该程序适用于高精度的场合
2.关于如何借鉴保加利亚程序的原则:
	首先,如果能完全看懂,则将原汇编程序改写为C程序;
	其次,如果大部分能看懂,则仍模仿汇编程序的
				结构和流程,改写。那些不懂的细节可以自己编写
				或者干脆暂时省略,以后出了问题再补充。
	最后,如果大部分看不懂,则自己创造,自己编写,
				同时借鉴汇编程序中可以看得懂的部分,以后出了
				问题再完善和补充。
*********************************/
/********************************
注意事项:
1.对AT24C02进行多次写操作时,中间必须相隔5ms
2.乘法运算时,乘数必须和积的数据类型相统一。
	注意:不同的数据类型进行运算时,极易出现隐蔽性的差错。
	要么定义为相同的数据类型,要么使用强制转换。
	另外,涉及到乘法运算时,存在着运算过程中,某个被乘数
	的变量的内容被“非法”修改的现象。
	如果碰上这种情况,重新赋值就可以了。
	通过单步调试来发现这个隐形杀手。
	
3.我们使用的晶振是11.0592M,不是12M,所以定时是不准确
	的,存在误差。
4.DATA的128个字节不能全部占用,因为堆栈也需要占用DATA
	的空间。因此可以将占用空间最大的数组存放在IDATA,
	其余变量都默认存放在DATA即可。 
5.制约响应速度的原因有两个:排序数组的长度和5460的
	输出速率。
6.CS5460A的偏置校准数据一旦写入偏置校准寄存器,要断电
	之后该寄存器的数据才消失。当然如果,每次运行程序都
	写入偏置校准数据,可能也不需要断电。	
7.单位转换中的克与英镑的转换存在bug,当秤的精度变大
	时会出现问题。示数的最高位与小数点的位置可能不正确
8.AT24C02的页面写操作存在不能超越当前page(8个字节);
   顺序写操作则没有这种限制。
9.分度值的改变牵连很广,包括:重量值的计算,精度,
	数值的符号的产生,长期稳定旗标。  
10.	 
*********************************/


/********************************
功能上的欠缺:	
1.还是校准完成后马上可以称重,比较人性化,但是代码
	可能会大量增加,因为,称重那部分很可能要重复。
	以后再尝试。
	也不一定,不妨尝试一下,我感觉应该也没有多少难度,
	代码也不会增加多少。
	建议方法:将菜单部分设计成一个庞大的函数。
						通过在称重循环结尾处查询组合键是否按下
						调用菜单函数。设定完成后通过break跳出
						菜单的循环,继续称重。
						当然读取24c02部分可能会重复。也
						可能不会。现炒现卖。
						暂时不用。
2.应该添加防震功能。
3.传说中的LCD亮度调节,就是背光亮度的调节,只要在硬件
	上调整相应的电阻就可以了。
	至于软件调节肯定要使用专门的液晶或者增加相关的硬件
	电路。
4.低电压报警模块应该并不难,但是,如果想要显示电压的
	数值则比较困难。要研究耀华T3的电路和软件才能解决。
5.目前没有hold功能,因为按键不够!
6.
7.	
8.我所使用的背光模块是一种手动背光,必须进行菜单设置。
	今后可能要考虑自动背光以及真正的手动按键控制背光。
9.
***************************************************/


/*************************************************
目前存在的问题
问题一:现在的背光电路有一个不爽的地方,开机就亮!
				建议方法:背光电路之前加一个三极管作为反相器
				就可以了。	
问题二:如果没有单位转换,小数点位置的变换会很简单,
				有单位转换,可能很麻烦。	
问题三:	
问题四:
				
问题五:T2作为波特率发生器,仿真失败;有可能是keil
				本身的模拟串口存在问题,不支持T2。如果进行
				实际的线路连接可能会成功。
				暂时使用T1作为串口波特率发生器;使用T0和T2
				实现延时5分钟的功能。	
问题六:
问题七:串口模块中,由于目前的示数的正负旗标:f_minus
				的局限性,当示数为0时,串口输出的数据会出现
				+0和-0两种情况。不过影响也不大,暂时不管它。															
**************************************************/


/***************************		
思路一:菜单所包含的内容暂时有以下几个:
				分度值选择、小数点的位置、波特率、背光开关
				
				、量程选择、校准、校准砝码。
				先模仿T3,归零范围选择和零点跟踪选择以后再说。				
思路二:	
思路三:新建LCD编码数组的过程中可能修改了某些数据,
				也不会出错,但是看着不爽。如果见到就改回来。
				
思路四:原来使用的sort函数中后来被去掉的部分应该有一定
				的防震功能。考虑一下是否恢复。
				在某个时间段之内的短暂的AD变化不去取样。
				建议方法:保加利亚程序中,在排序部分,那种间隔取值的
				方法研究一下。这种方法,在相同的排序数组长度
				的情况下,牺牲一部分时间,即LCD的变化速率
				翻倍,如果数组的长度是25,则称对瞬间冲力的忽略
				时间可达1~2秒。
				只要忽略时间达到2秒,防震功能就马马虎虎了。
				暂时不用,以后再说,因为我的RAM和ROM的空间
				都很有限。	
思路五:							
思路六:在菜单这部分,考虑使用位域,因为变量的值都
				比较小,即使使用最小的uchar也有点浪费。
				或者使用枚举
思路七:尽量减少变量,尽量减少全局变量。宁可增加子函数
				中的局部变量也要减少全局变量和主函数中的变量。
思路八:
思路九:			
思路十:考虑延时自动关机功能。也不复杂,只要在
    		时间到了之时,对OFF脚(P1.4)置零就能达到
    		关机的目的。
思路11:考虑分段校准。表头项目成功生产后再考虑提高。
思路12:			
思路13:				
思路14:
思路15:通过对比汇编产生的代码的多少,进行深层次的
				优化。																				
******************************/
#include <reg52.h>
#include <intrins.h>
//----------------------
//以下是自定义的数据类型
#define uchar  unsigned char
#define uint   unsigned int
#define ulong  unsigned long
struct AFEI
			 {
			 		ulong ad;
			 		uchar times;
			 };			 
//---------------------------------------------------------------------------------------------------------
//以下是HT1621模块的定义和声明
#define     BIAS_COM     0x29//0X52               //LCD 1/3偏压(bias) , 4公共口(com)。
//#define     RC256        0x18//0X30               //System clock source选择on-chip RC oscillator(256k)
																									//这条指令可以不要,因为1621上电默认的就是选择片内的RC256振荡器
#define     SYSTEN       0x01//0X02               //Turn on system oscillator(打开系统的振荡器)
#define     SYSDIS       0x00//0X00               //Turn off both system oscillator and LCD bias generator(全关)
#define     LCDON        0x03//0X06               //Turn on LCD
#define			LCDOFF			 0x02	//关闭LCD
#define			BUZON				 0x09//打开蜂鸣器
#define			BUZOFF			 0x08//关闭声音
#define			F_2K				 0x60//声音频率为2K
#define			F_4K				 0x40//声音频率为4K			
uchar code ID_CMD=0x04; 
uchar code ID_WR=0x05;
void wr_id(uchar id);
void wr_addr(uchar addr);
void wr_byte_1621(uchar dat_or_cmd);
void cmd_1621(uchar cmd);
void reset_1621(void);
void off_on_lcd(void);
void display_1621(void);
void alarm(uint time);
void delay_nms(uint n);
void delay_nus(char n);
//以上是HT1621的字型编码表,包括0-9,A、C、E、F、全部不显示、全部显示。
//uchar code discode[16]={0xbe,0x06,0x7c,0x5e,0xc6,0xda,0xfa,0x0e,0xfe,0xde,0xee,0xb8,0xf8,0xe8,0x00,0xff};
uchar code discode_num[10]={0xbe,0x06,0x7c,0x5e,0xc6,0xda,0xfa,0x0e,0xfe,0xde};
//以下是26个大写字母对应的HT1621的编码,为了方便查询,数组定义为27个字节,其中,首字节为特殊符号“=”的编码。
//以下是26个字母在数组中对应的下标。
//A-1,B-2,C-3,D-4,E-5,F-6,G-7,H-8,I-9,J-10,K-11,L-12,M-13,N-14;
//O-15,P-16,Q-17,R-18,S-19,T-20,U-21,V-22,W-23,X-23,Y-25,Z-26;
uchar code discode_cap[27]={0x50,0xee,0x00,0xb8,0x00,0xf8,0xe8,0x00,0xe6,0x00,0x00,0x00,0xb0,0x00,0x00,0xbe,0xec,0x00,0x00,0xda,0x00,0xb6,0x00,0x00,0x00,0x00,0x00};
uchar code discode_low[27]={0x50,0x00,0xf2,0x70,0x76,0x00,0x00,0xde,0xe2,0x00,0x00,0x00,0x00,0x00,0x62,0x72,0xec,0xce,0x60,0x00,0xf0,0x32,0x00,0x00,0x00,0xd6,0x00};
//定义一个HT1621显示数据缓冲区,初始化全部为0x00。
uchar dis_zone[6]={0x00,0x00,0x00,0x00,0x00,0x00};
sbit dt_1621=P2^4;   //LCD显示的数据。
sbit cs_1621=P2^5;   //使能。
sbit wr_1621=P2^6;   //写信号。
sbit BL=P1^6;//背光引脚,为1,背光亮;
											//为0,背光灭		
//------------------------------------
//以下是CS5460的变量定义和函数声明
sbit reset_5460=P1^0;
sbit sdo_5460=P1^1;
sbit sclk_5460=P1^2;
sbit sdi_5460=P1^3;
void cmd_5460(uchar cmd);
ulong read_5460(void);
void write_5460(ulong dat);
ulong buf_5460;
//-----------------------------------
//以下是串口的函数声明
/*********************************
	串口帧信息格式:一帧10位,
				其中第1位:起始位“0”
						第10位:停止位“1”
						中间8位:数据位
注意:一帧虽然在时序上有十位,包含起始位和停止位。
			但是,向sbuf赋值的实际上只有中间的8位数据位。						
********************************/		
/********************************
LCD显示的重量信息100.00Kg
串口发送的数据:”00.001 “,注意:最后的空格表示正号。
LCD显示的重量信息-35.000Kg
串口发送的数据:”000.53-“,注意:最后的"-"表示负号。
包含小数点和符号,共7位数据。并且二者的顺序恰好相反
另外:重量数字中高位为零不显示的情况,传送时按0发送
			凑够位数。



*******************************/												
void send_byte(uchar txd);
/******************************
//常用的ASCII码:		0	:48
										=:61	
										.	:46
										-:45
										g	:103
										K	:75
								空格” “:32
******************************/	
//------------------------------------
//以下是定时器(计数器)的管脚定义和函数声明
/************************************
为了实现延时5分钟,	T0作为16位定时器
										T1作为16位计数器	
************************************/
sbit CLK_COUNTER0=P3^4;
void delay_5min(void);
							
//------------------------------------
//以下是AT24c02的相关变量和函数
uchar	code READ=0xa1;		// 器件地址以及读取操作
uchar	code WRITE=0xa0;		// 器件地址以及写入操作
sbit SDA=P2^1;			// IIC数据
sbit SCL=P2^2;			// IIC时钟
void start(void);
void stop(void);
void ack(void);
void not_ack(void);
void write(uchar data_wr);
//void wr_byte(uchar addr_sla,uchar addr_wr,uchar data_byte);
void wr_nbyte(uchar addr,void *p_arr,uchar n);
//void wr_page(uchar addr_wr);
uchar rd_cur(void);
void rd_seq(uchar addr_rd,void *p_bufrd,uchar n);
//ulong rd_long(uchar addr_rd);
ulong idata buf_24c02_AD[2];																									
/*****************************
数组buf_24c02_rd[]中相应位置的数据含义:
								0——分度值
								1——小数点位置
								2——波特率
								3——背光								
*****************************/
uchar idata buf_24c02_4B[4];//用来存储从24c02中读取的数据,
														//随后就用来存储将要向24c02中写入的数据
														//目的:1.在菜单状态下,显示当前的设定
																	//2.在称重状态下,获取设定信息
																	//	用于显示和计算。	
//下面数组的用途:
//第一个:量程;第二个:校准砝码的重量
ulong idata buf_24c02_2L[2];
//--------------------------------------------
//电池电压检测部分的变量定义和函数声明。
sbit PD=P1^5;
void alarm_low(void);


//--------------------------------------------
//下面的数据是针对3公斤传感器(1.5Kg校准,没有偏置校准)
//电流通道增益PGA=50
//这种情况下,AD值太大,因此将从5460读出的数据
//在原来的基础上缩小为原来的1/4
//校准的AD平均值增量是:76477
#define N_5460 500  //表示5460的转换周期
//注意:下述带参数的宏定义中的x表示量程的AD平均值增量
#define ZERO_POS(x) ((x)/5) 	//表示零点范围上限:+20%
//#define ZERO_NEG(x) ((-1)*((x)/25)) 	//表示零点范围下限:-4%,这两个百分比都是以校准的AD平均值增量为分母的。
#define ZERO_NEG(x) (((-x)/25)) 	//表示零点范围下限:-4%,这两个百分比都是以校准的AD平均值增量为分母的。
#define MANU_ZERO_POS(x) ((x)/50)	//表示手动归零范围上限:+2%
//#define MANU_ZERO_NEG(x) ((-1)*((x)/50))	//表示手动归零范围下限:-2%,这两个百分比都是以校准的AD平均值增量为分母的。
#define MANU_ZERO_NEG(x) ((-x)/50)	//表示手动归零范围下限:-2%,这两个百分比都是以校准的AD平均值增量为分母的。
#define AUTO_ZERO_POS(x) ((x)/200)	//表示自动归零范围上限:+0.5%
//#define AUTO_ZERO_NEG(x) ((-1)*((x)/200))	//表示自动归零范围下限:-0.5%,这两个百分比都是以校准的AD平均值增量为分母的。						
#define AUTO_ZERO_NEG(x) ((-x)/200)	//表示自动归零范围下限:-0.5%,这两个百分比都是以校准的AD平均值增量为分母的。
#define TARE_HIGH(x) (x) //表示去皮的上限:量程的50%
#define TARE_LOW 5		 //表示去皮的下限
#define E 5	//表示通常我们所说的一个E。
#define E1(x) ((x)*E)
#define OVER_LOAD(x) ((x)+E*9+(long)(buf_24c02_AD[0]))//表示秤量程AD值上限,比量程AD高约9个E。														









//#define OFFSET 0x00fba48e  //表示5460的偏置校准数据
//#define JZ_ZERO_LOW 10000	//表示5460AD校准,空载时的下限
//#define JZ_ZERO_HIGH 20000	//表示5460AD校准,空载时的上限
//#define JZ_LOAD_LOW 90000	//表示5460AD校准,加砝码后的下限
//#define JZ_LOAD_HIGH 100000 	//表示5460AD校准,加砝码后的上限
//#define ZERO_POS 15295	//表示零点范围上限:+20%
//#define ZERO_NEG -3059	//表示零点范围下限:-4%,这两个百分比都是以校准的AD平均值增量为分母的。
//#define MANU_ZERO_POS	1530//表示手动归零范围上限:+2%
//#define MANU_ZERO_NEG	-1530//表示手动归零范围下限:-2%,这两个百分比都是以校准的AD平均值增量为分母的。
//#define AUTO_ZERO_POS	382//表示自动归零范围上限:+0.5%
//#define AUTO_ZERO_NEG	-382//表示自动归零范围下限:-0.5%,这两个百分比都是以校准的AD平均值增量为分母的。						
//#define TARE_HIGH 38239//表示去皮的上限:量程的50%
//#define TARE_LOW  5		 //表示去皮的下限	
//#define OVER_LOAD 100000		//表示秤量程AD值上限,比量程AD高约9个E。
														//这个宏定义今后可以省略。
//#define E 5	//表示通常我们所说的一个E。
//#define N 15000	//表示精度,即我自己平时所说的几万分之一或几千分之一。


/*****************************************************
//下面的数据是针对3公斤传感器(1Kg校准,没有偏置校准)
//电流通道增益PGA=50
//这种情况下,AD值太大,因此将从5460读出的数据
//在原来的基础上缩小为原来的1/4
//校准的AD平均值增量是:
#define N_5460 375  //表示5460的转换周期
//#define OFFSET 0x00fba48e  //表示5460的偏置校准数据
#define JZ_ZERO_LOW 10000	//表示5460AD校准,空载时的下限
#define JZ_ZERO_HIGH 20000	//表示5460AD校准,空载时的上限
#define JZ_LOAD_LOW 60000	//表示5460AD校准,加砝码后的下限
#define JZ_LOAD_HIGH 70000 	//表示5460AD校准,加砝码后的上限
#define ZERO_POS 15295	//表示零点范围上限:+20%
#define ZERO_NEG -3059	//表示零点范围下限:-4%,这两个百分比都是以校准的AD平均值增量为分母的。
#define MANU_ZERO_POS	1530//表示手动归零范围上限:+2%
#define MANU_ZERO_NEG	-1530//表示手动归零范围下限:-2%,这两个百分比都是以校准的AD平均值增量为分母的。
#define AUTO_ZERO_POS	382//表示自动归零范围上限:+0.5%
#define AUTO_ZERO_NEG	-382//表示自动归零范围下限:-0.5%,这两个百分比都是以校准的AD平均值增量为分母的。						
#define TARE_HIGH 38239//表示去皮的上限:量程的50%
#define TARE_LOW  5		 //表示去皮的下限	
#define OVER_LOAD 100000		//表示秤量程AD值上限,比量程AD高约9个E。
														//这个宏定义今后可以省略。
#define E 5	//表示通常我们所说的一个E。
#define N 10000	//表示精度,即我自己平时所说的几万分之一或几千分之一。
************************************************************************/



/*****************************************
错误号说明:(注意:针对错误号使用搜索,不行!)
Err 1:	零点偏离了指定范围
Err 2:	单位转换
Err 3:	菜单
Err 4: 	超载
Err 5: 	校准时空载的AD平均值超出了范围
Err 6: 	校准时,放置校准砝码后的AD平均值超出了范围
Err 7:	菜单中的分度值或者称重时分度值选择
Err 8:	菜单中的波特率或者称重时波特率选择			
*******************************************/
/******************************************
秤的状态符号说明如下:
F1:表征稳定
F2:表征HOLD锁定
F5:表征去皮状态
F6:表征示数归零
电池符号:表示电量不足
F4:暂时表示f_x1
F3:暂时表示重量累加
******************************************/
//以下是全局变量和数据处理过程中使用到的函数
bit bdata f_stab_weight=0;//表征称重结果示数的稳定
													//为1,示数稳定;
													//为0,示数不稳
bit bdata f_stab=0;		//表征结果的稳定(相邻两个AD),
											//为0,表示稳定;
											//为1,表示不稳定
bit bdata f_stab2=0;	//表征结果的稳定(间隔的两个AD),
											//为0,表示稳定;
											//为1,表示不稳定	
bit bdata f_hold=0;//表征是否开启了锁定功能
										//为0,表示没有锁定示数;
										//为1,表示已经锁定了称重示数

bit bdata f_tare=0;//表征去皮状态,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -