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)
2022-3-9 17:25 上傳
點擊文件名下載附件
|