Altium Designer画的PCB图如下:(51hei附件中可下载工程文件)
单片机源程序如下:
- /*************************************************
- /********************************************************************
- ***********主题:基于51单片机电子称c程序设计
- ***********功能: 可以输出量程为5kg物体的重量并且结合键盘单价的输入计算
- *********** 出价格,还具有去皮、休眠、切换量程等功能,输出的重量和
- *********** 总额采用四舍五入
- *********************************************************************/
- #include "Main.h"
- bit g_DecimalPointflag = 0, KeycanFlag = 0, RangeFlag = 0, TotalFlag = 0; //小数点按下标志位,数字按键按下标志位,量程切换标志位
- sbit Beep = P1^3; //蜂鸣器报警
- sbit Led = P1^4; //报警LED
- sbit RATE = P2^5; //转换速率调节
- UINT_16 g_HighPrice = 0; //输入单价存储整数部分变量
- UINT_8 g_LowPrice = 0; //输入单价存储小数点后部分变量
- UINT_8 Count1 = 0, Count2 = 0, DecimalPointCount = 0; //Count1限定输入单价整数部分的次数(限定为5位数,超过自动清零),Count限定为两位小数,超过自动清零
- FLOAT_32 g_Price = 0.0; //物品单价(整数与小数之和)
- UINT_32 g_TotalPrices = 0; //物品总额
- FLOAT_32 g_TempPrices = 0.0; //总额中间变量(防止总额过大超出液晶屏显示,超出时警告)
- UINT_8 code table1[] = {"欢迎你"};
- UINT_8 code table2[] = {"重量G: g"};
- UINT_8 code table3[] = {"单价$:"};
- UINT_8 code table4[] = {"总额$:"};
- UINT_8 code table5[] = {"Err!"};
- UINT_8 code table6[] = {" "}; //清屏的某一行
- UINT_8 code table7[] = {"重量G:0.000Kg"};
- UINT_8 code table8[] = {"0.000"}; //用空格会引起闪烁感
- UINT_8 WeightTable[6]; //存储质量的字符串
- UINT_8 TotalPricesTable[11]; //存储总额字符串
-
- void Init(void); //初始化函数
- void Clean_Price(void); //清除函数
- void Display_Int2str(UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM); //输入十进制显示字符函数
- void Init_Weighttab(UINT_8 *String1, UINT_8 *String2); //初始化字符串数组
- void main()
- {
- INT_8 j = 0, k = 0, count = 0;
- UINT_8 Key = 0, Num = 0; //Key存储按键的键值,Num存储按下的是那个数字
- UINT_32 tmp = 0;
- Init();
- while (1)
- {
- WDT_FeedDog(); //喂狗
- if (KeycanFlag == 0) //价格还没输入时可以显示(防止价格输入一半DDRAM地址改变,造成价格不可连续输入)
- {
- if (TimeCount >= 50) //定时时间超过250ms执行AD采集
- {
- // Offset = AD_Hx711(); //8527820-8475960 =51860
- // Display_Int2str(Offset, WeightTable, 0x93);
- WeightTemp = AD_Weight(AD_Hx711()); //把AD值转化为以克为单位的质量(含小数)
- if (WeightTemp > 4000) //超出量程4000g报警
- {
- for (k = 0; k < 4; k++)
- {
- LcdDdram_Display(1,3,table5); //输出错误字符串
- }
- Beep = 0; //蜂鸣器鸣叫
- Led = 0; //Led亮
- }
- else
- {
- Beep = 1; //重量少于最大量程关闭蜂鸣器
- Led = 1;
- tmp = (UINT_32)(WeightTemp); // tmp = (UINT_32)(WeightTemp + 0.5); //将质量四舍五入,例如1000.50 》1001
- if(RangeFlag == 0) //量程单位为g
- {
- Init_Weighttab(WeightTable,table6); //初始化字符数组为空格,防止上次字符位数比这次大,没有清除
- k = 0; //例如上次显示1234,这次12,残留34
- Weight = tmp; //中间质量变量赋给质量
- while (tmp != 0)
- {
- WeightTable[k++] = 0x30 + tmp % 10; //提取十进制最后一位转换为字符
- tmp /= 10;
- }
- if (k == 0) //质量为0时
- {
- WeightTable[k++] = '0';
- }
- Write_Cmd(0x93);
- count = k;
- while (k > 0)
- {
- Write_Data(WeightTable[k-1]); //质量倒序输出,因为之前是倒序输入,高位地址为高位,由高位到低位
- k--;
- }
- for (k = count; k < 5; k++ ) //把上次残留的字符清掉
- {
- Write_Data(WeightTable[k]);
- }
- }
- else
- {
- Init_Weighttab(WeightTable,table8); //清空字符串数组
- k = 0;
- Weight = tmp / 1000.0; //质量/g 1000 = /kg
- while (tmp != 0)
- {
- WeightTable[k++] = 0x30 + tmp % 10;
- tmp /= 10;
- if (k == 3) //i=3时就是获得3位小数时插入小数点
- {
- WeightTable[k] = '.';
- k += 1;
- }
- }
- if (k == 4) //刚好3个小数补0 0.123
- {
- WeightTable[k] = '0';
- k++; //和上面统一,k比实际大1,下面再减回
- }
- if (k < 3) //当不够两位小数时,例如1实际代表的是0.01
- {
- WeightTable[4] = 0x30; //在最高位插入0
- WeightTable[3] = '.'; //在最次高位插入.
- for (j = k; j < 3; j++)
- {
- WeightTable[j] = 0x30; //如果只有0位时插入一个插入两个0 0.00
- } //如果只有1位时插入一个插入1个0 0.0
- k = 5; //0.001刚好5个数
- }
- Write_Cmd(0x93); //重定位液晶DDRAM地址
- while (k > 0)
- {
- Write_Data(WeightTable[k-1]); //总额结算,倒序输出,因为之前是倒序输入,高位地址为高位
- k--;
- }
-
- }
-
- }
- TimeCount = 0;
- Write_Cmd(0x8b); //显示完体重就定位价格显示地址
- }
- }
-
- if (TimeIRQflag == 1) //5ms定时中断 ,5ms是为了可以利用来去抖延时而不失效率,由扫描态转入确认态至少5ms
- {
- TimeIRQflag = 0;
- Key = KeyRead(); //键盘扫描,获取键值 按键的意义: 1 2 3 量程切换
- switch (Key) // 4 5 6 去皮
- { // 7 8 9 清除
- case KEY1 : if (TotalFlag== 0) { Write_Data(0x31); Num = 1; } break; // . 0 开关 结算
- case KEY2 : if (TotalFlag== 0) { Write_Data(0x32); Num = 2; } break;
- case KEY3 : if (TotalFlag== 0) { Write_Data(0x33); Num = 3; } break;
- case KEY4 :
- {
- RangeFlag = !RangeFlag ;
- Clean_Price();
- if (RangeFlag == 0) //量程切换模式,0为g为单位,1为Kg为单位
- {
- LcdDdram_Display(1,0,table2); //把字符串Kg 变成 g ,残留1个g
- Write_Data(' '); //清掉残留的g
- }
- else
- {
- LcdDdram_Display(1,0,table7); //把字符串g 变成 Kg
- }
- Write_Cmd(0x8b);
- }
- break;
- case KEY5 : if (TotalFlag== 0) { Write_Data(0x34); Num = 4;} break;
- case KEY6 : if (TotalFlag== 0) { Write_Data(0x35); Num = 5;} break;
- case KEY7 : if (TotalFlag== 0) { Write_Data(0x36); Num = 6;} break;
- case KEY8 : AD_Offset(); break;
- case KEY9 : if (TotalFlag== 0) { Write_Data(0x37); Num = 7;} break;
- case KEY10 : if (TotalFlag== 0) { Write_Data(0x38); Num = 8;} break;
- case KEY11 : if (TotalFlag== 0) { Write_Data(0x39); Num = 9;} break;
- case KEY12 : Clean_Price(); break;
- case KEY13 :
- {
- if (DecimalPointCount == 0 && KeycanFlag == 0)
- {
- Write_Data(0x30);
- Write_Data(0x2e); //显示‘.’
- }
- if (DecimalPointCount == 0 && KeycanFlag == 1)
- {
- Write_Data(0x2e);
- }
- if (DecimalPointCount > 200)
- {
- DecimalPointCount = 0;
- }
- DecimalPointCount++;
- g_DecimalPointflag = 1; //小数点按下
- KeycanFlag = 1;
- }
- break;
- case KEY14 : if (TotalFlag== 0) { Write_Data(0x30); Num = 0; } break;
- case KEY15 : PCON_PD(); break;
- case KEY16 :
- {
- TotalFlag = 1; //总额显示之后不能输入价格
- if (Count1 == 1)
- {
- Count1 = 0; //小数点后面只有1位数的时候*10
- g_LowPrice *= 10; //变大10倍,防止出现例如输入1.2的时候,小数部分为0.02
- }
- g_Price = g_HighPrice + g_LowPrice / 100.0; //单价 = 整数 + 小数
- g_TempPrices = g_Price * Weight * 100; //总额中间变量 = 价格 * 重量 * 100(保留两位小数点)
- if (g_TempPrices >999999999) //超出屏幕显示(10位,1位为小数点)报警
- {
- LcdDdram_Display(3,3,table5); //超出量程报错
- break;
- } //(int)(a+0.5)为四舍五入
- g_TotalPrices = (UINT_32)(g_TempPrices+0.5); //把浮点型转换为整型,2.10*1*100 = 209.99 (优化出错)!!!!
- Display_Int2str(g_TotalPrices, TotalPricesTable, 0x9b); //显示总额
- }
- break;
- default : break;
- }
-
- if (Key == KEY1 || Key == KEY2 || Key == KEY3 || Key == KEY5 || Key == KEY6 //有数字按键按下时
- || Key == KEY7 || Key == KEY9 || Key == KEY10 || Key == KEY11 || Key == KEY14)
- {
- KeycanFlag = 1;
- if (g_DecimalPointflag != 1) //数字按下时小数点还没按下输入的是整数部分
- {
- Count2++;
- if (Count2 >= 5) //不可以输入超过5位数
- {
- Clean_Price(); //超过自动清零
- }
- g_HighPrice = g_HighPrice * 10 + Num; //连续输入整数部分时,前一位*10再+后一位
- }
- else //有小数点按下了
- {
- Count1++;
- if (Count1 >= 3) //小数部分不可以输入超过2位数
- {
- Clean_Price(); //超过自动清零
- }
- g_LowPrice = g_LowPrice * 10 + Num;
-
- }
- }
-
- }
- }
- }
-
- /********************************************************************
- 函数名称: Init()
- 功能简介: 初始化定时器,液晶初始化
- 入口参数: 无
- 返回值 :无
- *********************************************************************/
- void Init(void)
- {
- RATE = 0; //初始化Hx711转换速率为10Hz(RATE = 0时AD转换速率为10Hz,RATE = 1为80Hz)
- Time_Init(); //定时器0中断初始化
- LCD_Init(); //12864液晶初始化
- LcdDdram_Display(0,0,table1); //第1行显示数据table1内容 (万家福超市欢迎你)
- LcdDdram_Display(1,0,table2); //第2行显示数据table2内容 (重量G: g)
- LcdDdram_Display(2,0,table3); //第3行显示数据table3内容 (单价$:)
- LcdDdram_Display(3,0,table4); //第4行显示数据table4内容 (总额$:)
- AD_Offset(); //采集零偏的平均值
- }
- /********************************************************************
- 函数名称: void Clean_Price(void)
- 功能简介: 清除函数,把单价、总额变量等清0
- 入口参数: 无
- 返回值 :无
- *********************************************************************/
- void Clean_Price(void)
- {
- LcdDdram_Display(2,3,table6); //清除单价显示
- LcdDdram_Display(3,3,table6); //清除总额显示
- g_HighPrice = 0; //清除价格
- g_LowPrice = 0;
- Count1 = 0;
- Count2 = 0;
- KeycanFlag = 0; //清除禁止AD采集标志位
- TotalFlag = 0;
- DecimalPointCount = 0;
- g_DecimalPointflag = 0; //小数点
- Write_Cmd(0x8b); //DDRAM地址指针调整
- }
- /********************************************************************
- 函数名称: void Display_Int2str(UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM)
- 功能简介: 把十进制数转换为字符串输出,保留两位小数点
- 此段代码是把十进制的“总额”倒序转换为字符串存放在数组TotalPricesTable【】里面,
- 总额TotalPrices的LSB位存放在字符数组的最低位,这样做的原因有两点:
- 可以确定小数点存放在数组那个位置(由保留小数点位数(i)确定,从最低位数0起到第i位插入小数点)
- 如果设定12864液晶为地址自动减1模式时为小端字节,例如把654321倒序输出就会变成214365
- 入口参数: UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM
- 返回值 :无
- *********************************************************************/
- void Display_Int2str(UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM)
- {
- INT_8 i = 0, j = 0;
- while (DecNum != 0) //十进制数不为0时
- {
- Str[i++] = 0x30 + DecNum % 10; //提取十进制最后一位转换为字符
- DecNum /= 10;
- if (i == 2) //倒序存储到Str数组里去,例如1234,存放为4321
- {
- Str[i] = '.'; //i=2时就是获得两位小数时插入小数点
- i+=1;
- }
- }
- if (i == 3) //Str只有两位数时,在最前面插入‘0’
- {
- Str[i] = '0';
- i++;
- }
- Write_Cmd(DDRAM); //重定位液晶DDRAM地址
- if (i < 2) //当不够两位小数时,例如1实际代表的是0.01
- {
- Str[3] = 0x30; //在最高位插入0
- Str[2] = '.'; //在最次高位插入.
- for (j = i; j < 2; j++)
- {
- Str[j] = 0x30; //如果只有0位时插入一个插入两个0 0.00
- } //如果只有1位时插入一个插入1个0 0.0
- i = 4; //字符数组TotalPricesTable长度
- }
- while (i >= 1) //i设定大于1不大于0是因为前面的i在不符合循环条件时自动加1,比实际字符数组长度多1位
- {
- Write_Data(Str[i-1]); //总额结算,倒序输出,因为之前是倒序输入,高位地址为高位
- i--;
- }
- }
- /********************************************************************
- 函数名称: Init_Weighttab()
- 功能简介: 初始化字符数组
- 入口参数: UINT_8 *String1, UINT_8 *String2
- 返回值 :无
- *********************************************************************/
- void Init_Weighttab(UINT_8 *String1, UINT_8 *String2 )
- {
- UINT_8 i;
- for (i = 0; i < 5 ;i++)
- {
- *String1++ = *String2;
- }
- }
-
复制代码
Keil代码PCB 2个文件下载:
电子秤.7z
(664.39 KB, 下载次数: 29)
|