標(biāo)題:
基于51單片機(jī)電子秤PCB與源代碼
[打印本頁(yè)]
作者:
fdhfghg
時(shí)間:
2022-3-2 20:47
標(biāo)題:
基于51單片機(jī)電子秤PCB與源代碼
Altium Designer畫的PCB圖如下:(51hei附件中可下載工程文件)
51hei.png
(49.53 KB, 下載次數(shù): 44)
下載附件
2022-3-9 17:22 上傳
單片機(jī)源程序如下:
/*************************************************
/********************************************************************
***********主題:基于51單片機(jī)電子稱c程序設(shè)計(jì)
***********功能: 可以輸出量程為5kg物體的重量并且結(jié)合鍵盤單價(jià)的輸入計(jì)算
*********** 出價(jià)格,還具有去皮、休眠、切換量程等功能,輸出的重量和
*********** 總額采用四舍五入
*********************************************************************/
#include "Main.h"
bit g_DecimalPointflag = 0, KeycanFlag = 0, RangeFlag = 0, TotalFlag = 0; //小數(shù)點(diǎn)按下標(biāo)志位,數(shù)字按鍵按下標(biāo)志位,量程切換標(biāo)志位
sbit Beep = P1^3; //蜂鳴器報(bào)警
sbit Led = P1^4; //報(bào)警LED
sbit RATE = P2^5; //轉(zhuǎn)換速率調(diào)節(jié)
UINT_16 g_HighPrice = 0; //輸入單價(jià)存儲(chǔ)整數(shù)部分變量
UINT_8 g_LowPrice = 0; //輸入單價(jià)存儲(chǔ)小數(shù)點(diǎn)后部分變量
UINT_8 Count1 = 0, Count2 = 0, DecimalPointCount = 0; //Count1限定輸入單價(jià)整數(shù)部分的次數(shù)(限定為5位數(shù),超過自動(dòng)清零),Count限定為兩位小數(shù),超過自動(dòng)清零
FLOAT_32 g_Price = 0.0; //物品單價(jià)(整數(shù)與小數(shù)之和)
UINT_32 g_TotalPrices = 0; //物品總額
FLOAT_32 g_TempPrices = 0.0; //總額中間變量(防止總額過大超出液晶屏顯示,超出時(shí)警告)
UINT_8 code table1[] = {"歡迎你"};
UINT_8 code table2[] = {"重量G: g"};
UINT_8 code table3[] = {"單價(jià)$:"};
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"}; //用空格會(huì)引起閃爍感
UINT_8 WeightTable[6]; //存儲(chǔ)質(zhì)量的字符串
UINT_8 TotalPricesTable[11]; //存儲(chǔ)總額字符串
void Init(void); //初始化函數(shù)
void Clean_Price(void); //清除函數(shù)
void Display_Int2str(UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM); //輸入十進(jìn)制顯示字符函數(shù)
void Init_Weighttab(UINT_8 *String1, UINT_8 *String2); //初始化字符串?dāng)?shù)組
void main()
{
INT_8 j = 0, k = 0, count = 0;
UINT_8 Key = 0, Num = 0; //Key存儲(chǔ)按鍵的鍵值,Num存儲(chǔ)按下的是那個(gè)數(shù)字
UINT_32 tmp = 0;
Init();
while (1)
{
WDT_FeedDog(); //喂狗
if (KeycanFlag == 0) //價(jià)格還沒輸入時(shí)可以顯示(防止價(jià)格輸入一半DDRAM地址改變,造成價(jià)格不可連續(xù)輸入)
{
if (TimeCount >= 50) //定時(shí)時(shí)間超過250ms執(zhí)行AD采集
{
// Offset = AD_Hx711(); //8527820-8475960 =51860
// Display_Int2str(Offset, WeightTable, 0x93);
WeightTemp = AD_Weight(AD_Hx711()); //把AD值轉(zhuǎn)化為以克為單位的質(zhì)量(含小數(shù))
if (WeightTemp > 4000) //超出量程4000g報(bào)警
{
for (k = 0; k < 4; k++)
{
LcdDdram_Display(1,3,table5); //輸出錯(cuò)誤字符串
}
Beep = 0; //蜂鳴器鳴叫
Led = 0; //Led亮
}
else
{
Beep = 1; //重量少于最大量程關(guān)閉蜂鳴器
Led = 1;
tmp = (UINT_32)(WeightTemp); // tmp = (UINT_32)(WeightTemp + 0.5); //將質(zhì)量四舍五入,例如1000.50 》1001
if(RangeFlag == 0) //量程單位為g
{
Init_Weighttab(WeightTable,table6); //初始化字符數(shù)組為空格,防止上次字符位數(shù)比這次大,沒有清除
k = 0; //例如上次顯示1234,這次12,殘留34
Weight = tmp; //中間質(zhì)量變量賦給質(zhì)量
while (tmp != 0)
{
WeightTable[k++] = 0x30 + tmp % 10; //提取十進(jìn)制最后一位轉(zhuǎn)換為字符
tmp /= 10;
}
if (k == 0) //質(zhì)量為0時(shí)
{
WeightTable[k++] = '0';
}
Write_Cmd(0x93);
count = k;
while (k > 0)
{
Write_Data(WeightTable[k-1]); //質(zhì)量倒序輸出,因?yàn)橹笆堑剐蜉斎耄呶坏刂窞楦呶,由高位到低?nbsp;
k--;
}
for (k = count; k < 5; k++ ) //把上次殘留的字符清掉
{
Write_Data(WeightTable[k]);
}
}
else
{
Init_Weighttab(WeightTable,table8); //清空字符串?dāng)?shù)組
k = 0;
Weight = tmp / 1000.0; //質(zhì)量/g 1000 = /kg
while (tmp != 0)
{
WeightTable[k++] = 0x30 + tmp % 10;
tmp /= 10;
if (k == 3) //i=3時(shí)就是獲得3位小數(shù)時(shí)插入小數(shù)點(diǎn)
{
WeightTable[k] = '.';
k += 1;
}
}
if (k == 4) //剛好3個(gè)小數(shù)補(bǔ)0 0.123
{
WeightTable[k] = '0';
k++; //和上面統(tǒng)一,k比實(shí)際大1,下面再減回
}
if (k < 3) //當(dāng)不夠兩位小數(shù)時(shí),例如1實(shí)際代表的是0.01
{
WeightTable[4] = 0x30; //在最高位插入0
WeightTable[3] = '.'; //在最次高位插入.
for (j = k; j < 3; j++)
{
WeightTable[j] = 0x30; //如果只有0位時(shí)插入一個(gè)插入兩個(gè)0 0.00
} //如果只有1位時(shí)插入一個(gè)插入1個(gè)0 0.0
k = 5; //0.001剛好5個(gè)數(shù)
}
Write_Cmd(0x93); //重定位液晶DDRAM地址
while (k > 0)
{
Write_Data(WeightTable[k-1]); //總額結(jié)算,倒序輸出,因?yàn)橹笆堑剐蜉斎,高位地址為高?br />
k--;
}
}
}
TimeCount = 0;
Write_Cmd(0x8b); //顯示完體重就定位價(jià)格顯示地址
}
}
if (TimeIRQflag == 1) //5ms定時(shí)中斷 ,5ms是為了可以利用來去抖延時(shí)而不失效率,由掃描態(tài)轉(zhuǎn)入確認(rèn)態(tài)至少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 開關(guān) 結(jié)算
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è)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; //小數(shù)點(diǎn)按下
KeycanFlag = 1;
}
break;
case KEY14 : if (TotalFlag== 0) { Write_Data(0x30); Num = 0; } break;
case KEY15 : PCON_PD(); break;
case KEY16 :
{
TotalFlag = 1; //總額顯示之后不能輸入價(jià)格
if (Count1 == 1)
{
Count1 = 0; //小數(shù)點(diǎn)后面只有1位數(shù)的時(shí)候*10
g_LowPrice *= 10; //變大10倍,防止出現(xiàn)例如輸入1.2的時(shí)候,小數(shù)部分為0.02
}
g_Price = g_HighPrice + g_LowPrice / 100.0; //單價(jià) = 整數(shù) + 小數(shù)
g_TempPrices = g_Price * Weight * 100; //總額中間變量 = 價(jià)格 * 重量 * 100(保留兩位小數(shù)點(diǎn))
if (g_TempPrices >999999999) //超出屏幕顯示(10位,1位為小數(shù)點(diǎn))報(bào)警
{
LcdDdram_Display(3,3,table5); //超出量程報(bào)錯(cuò)
break;
} //(int)(a+0.5)為四舍五入
g_TotalPrices = (UINT_32)(g_TempPrices+0.5); //把浮點(diǎn)型轉(zhuǎn)換為整型,2.10*1*100 = 209.99 (優(yōu)化出錯(cuò))。。!
Display_Int2str(g_TotalPrices, TotalPricesTable, 0x9b); //顯示總額
}
break;
default : break;
}
if (Key == KEY1 || Key == KEY2 || Key == KEY3 || Key == KEY5 || Key == KEY6 //有數(shù)字按鍵按下時(shí)
|| Key == KEY7 || Key == KEY9 || Key == KEY10 || Key == KEY11 || Key == KEY14)
{
KeycanFlag = 1;
if (g_DecimalPointflag != 1) //數(shù)字按下時(shí)小數(shù)點(diǎn)還沒按下輸入的是整數(shù)部分
{
Count2++;
if (Count2 >= 5) //不可以輸入超過5位數(shù)
{
Clean_Price(); //超過自動(dòng)清零
}
g_HighPrice = g_HighPrice * 10 + Num; //連續(xù)輸入整數(shù)部分時(shí),前一位*10再+后一位
}
else //有小數(shù)點(diǎn)按下了
{
Count1++;
if (Count1 >= 3) //小數(shù)部分不可以輸入超過2位數(shù)
{
Clean_Price(); //超過自動(dòng)清零
}
g_LowPrice = g_LowPrice * 10 + Num;
}
}
}
}
}
/********************************************************************
函數(shù)名稱: Init()
功能簡(jiǎn)介: 初始化定時(shí)器,液晶初始化
入口參數(shù): 無
返回值 :無
*********************************************************************/
void Init(void)
{
RATE = 0; //初始化Hx711轉(zhuǎn)換速率為10Hz(RATE = 0時(shí)AD轉(zhuǎn)換速率為10Hz,RATE = 1為80Hz)
Time_Init(); //定時(shí)器0中斷初始化
LCD_Init(); //12864液晶初始化
LcdDdram_Display(0,0,table1); //第1行顯示數(shù)據(jù)table1內(nèi)容 (萬(wàn)家福超市歡迎你)
LcdDdram_Display(1,0,table2); //第2行顯示數(shù)據(jù)table2內(nèi)容 (重量G: g)
LcdDdram_Display(2,0,table3); //第3行顯示數(shù)據(jù)table3內(nèi)容 (單價(jià)$:)
LcdDdram_Display(3,0,table4); //第4行顯示數(shù)據(jù)table4內(nèi)容 (總額$:)
AD_Offset(); //采集零偏的平均值
}
/********************************************************************
函數(shù)名稱: void Clean_Price(void)
功能簡(jiǎn)介: 清除函數(shù),把單價(jià)、總額變量等清0
入口參數(shù): 無
返回值 :無
*********************************************************************/
void Clean_Price(void)
{
LcdDdram_Display(2,3,table6); //清除單價(jià)顯示
LcdDdram_Display(3,3,table6); //清除總額顯示
g_HighPrice = 0; //清除價(jià)格
g_LowPrice = 0;
Count1 = 0;
Count2 = 0;
KeycanFlag = 0; //清除禁止AD采集標(biāo)志位
TotalFlag = 0;
DecimalPointCount = 0;
g_DecimalPointflag = 0; //小數(shù)點(diǎn)
Write_Cmd(0x8b); //DDRAM地址指針調(diào)整
}
/********************************************************************
函數(shù)名稱: void Display_Int2str(UINT_32 DecNum, UINT_8 Str[], UINT_8 DDRAM)
功能簡(jiǎn)介: 把十進(jìn)制數(shù)轉(zhuǎn)換為字符串輸出,保留兩位小數(shù)點(diǎn)
此段代碼是把十進(jìn)制的“總額”倒序轉(zhuǎn)換為字符串存放在數(shù)組TotalPricesTable【】里面,
總額TotalPrices的LSB位存放在字符數(shù)組的最低位,這樣做的原因有兩點(diǎn):
可以確定小數(shù)點(diǎn)存放在數(shù)組那個(gè)位置(由保留小數(shù)點(diǎn)位數(shù)(i)確定,從最低位數(shù)0起到第i位插入小數(shù)點(diǎn))
如果設(shè)定12864液晶為地址自動(dòng)減1模式時(shí)為小端字節(jié),例如把654321倒序輸出就會(huì)變成214365
入口參數(shù): 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) //十進(jìn)制數(shù)不為0時(shí)
{
Str[i++] = 0x30 + DecNum % 10; //提取十進(jìn)制最后一位轉(zhuǎn)換為字符
DecNum /= 10;
if (i == 2) //倒序存儲(chǔ)到Str數(shù)組里去,例如1234,存放為4321
{
Str[i] = '.'; //i=2時(shí)就是獲得兩位小數(shù)時(shí)插入小數(shù)點(diǎn)
i+=1;
}
}
if (i == 3) //Str只有兩位數(shù)時(shí),在最前面插入‘0’
{
Str[i] = '0';
i++;
}
Write_Cmd(DDRAM); //重定位液晶DDRAM地址
if (i < 2) //當(dāng)不夠兩位小數(shù)時(shí),例如1實(shí)際代表的是0.01
{
Str[3] = 0x30; //在最高位插入0
Str[2] = '.'; //在最次高位插入.
for (j = i; j < 2; j++)
{
Str[j] = 0x30; //如果只有0位時(shí)插入一個(gè)插入兩個(gè)0 0.00
} //如果只有1位時(shí)插入一個(gè)插入1個(gè)0 0.0
i = 4; //字符數(shù)組TotalPricesTable長(zhǎng)度
}
while (i >= 1) //i設(shè)定大于1不大于0是因?yàn)榍懊娴膇在不符合循環(huán)條件時(shí)自動(dòng)加1,比實(shí)際字符數(shù)組長(zhǎng)度多1位
{
Write_Data(Str[i-1]); //總額結(jié)算,倒序輸出,因?yàn)橹笆堑剐蜉斎耄呶坏刂窞楦呶?br />
i--;
}
}
/********************************************************************
函數(shù)名稱: Init_Weighttab()
功能簡(jiǎn)介: 初始化字符數(shù)組
入口參數(shù): 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;
}
}
復(fù)制代碼
Keil代碼PCB 2個(gè)文件下載:
電子秤.7z
(664.39 KB, 下載次數(shù): 29)
2022-3-9 17:25 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1