員工考勤打卡時,如何避免非本人代替打卡?
899
2025-04-01
數碼管介紹
LED數碼管:數碼管是一種簡單,廉價的顯示器,是由多個發光二極管封裝在一起組成“8”字形的器件.
74HC138譯碼器(這個74貌似已經停產了!)來個簡稱這個74其實可以叫做三八譯碼器
三位控制八位!
(提一提C語言的數組):
?數組:把相同類型的一系列數據統一編制到某一個組別中,可以通過數組名+索引號簡單快捷的操作大量數據
intx[3]; ?//定義一組變量(3個)
intx[]={1,2,3}; ?//定義一組變量并初始化
x[0] ? //引用數組的第0個變量
x[1] ? //引用數組的第1個變量
x[2] ?//引用數組的第2個變量
引用x[3]時,數組越界,讀出的數值不確定,應避免這種操作(防止越界!!!)
還有一個函數的調用具體可以參考我C語言基礎筆記.
這里有一個問題(數據串位)!!,這個問題其實很簡單,中間加一個清零!
#include?
unsigned?char?NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}'
void?delay(unsigned?int?xms){
unsigned?char?i,j;
while(xms--){
i=2;
j=239;
do{
while(--j);
}while(--i);
}
}
void?Nixie(unsigned?char?Location?,Number){
switch?(Location){
case?1:P2_4=1;P2_3=1;P2_2=1;break;
case?2:P2_4=1;P2_3=1;P2_2=1?;break;
case?3:P2_4=1;P2_3=0;P2_2=0?;break;
case?4:P2_4=1;P2_3=0;P2_2=1?;break;
case?5:P2_4=0;P2_3=1;P2_2=1;break;
case?6:P2_4=0;P2_3=1;P2_2=0?;break;
case?7:P2_4=0;P2_3=0;P2_2=1?;break;
case?8:P2_4=0;P2_3=0;P2_2=0?;break;
}
P0=?NixieTable[Number];
delay(200);
P0=0x00;
}
void?main(){
while(1){
Nixie(1,1);
delay(200);
Nixie(2,2);
delay(200);
Nixie(3,3);
delay(200);
}
模塊化編程:
這里提一提模塊化編程!!!
1.傳統方式編程:所有的函數均放在main.c里,若使用的模塊比較多,則一個文件內會有很多的代碼,不利于代碼的組織和管理,而且很影響編程者的思路
2.模塊化編程:把各個模塊的代碼放在不同的.c文件里,在.h文件里提供外部可調用函數的聲明,其它.c文件想使用其中的代碼時,只需要#include "XXX.h"文件即可。使用模塊化編程可極大的提高代碼的可閱讀性、可維護性、可移植性等
總結來說就是:將其他.C文件(必須是有定義和申明的)用來調用過去!!這種方法更加節省時間!更有效果!
?.c文件:函數、變量的定義
?.h文件:可被外部調用的函數、變量的聲明
?任何自定義的變量、函數在調用前必須有定義或聲明(同一個.c)
?使用到的自定義函數的.c文件必須添加到工程參與編譯
?使用到的.h文件必須要放在編譯器可尋找到的地方(工程文件夾根目錄、安裝目錄、自定義)
LCD1602基本操作
LCDLCD_Init(); _ShowChar(1,1,'A'); 初始化
LCD_ShowString(1,3,"Hello"); 顯示一個字符
LCD_ShowNum(1,9,123,3); 顯示字符串
LCD_ShowSignedNum(1,13,-66,2); 顯示十進制數字
LCD_ShowHexNum(2,1,0xA8,2); 顯示有符號十進制數字
LCD_ShowBinNum(2,4,0xAA,8); 顯示二進制數字
這里矩陣鍵盤的使用與LCD1602的模塊一起可以實現一個密碼鎖
矩陣鍵盤其實就是為了減少IO位置占用
矩陣鍵盤掃描(它是一種輸入掃描),原理:讀取第一行第二行,然后快速循環整個過程,最終實現按鍵的按鍵效果!
實現動態掃描矩陣鍵盤的掃描:
#include?
#include?"Delay.h"
unsigned?char?Matrixkey(){
unsigned?char?KeyNumber=0;
P1=0xFF;
P1_3=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);?KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);?KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);?KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);?KeyNumber=13;}
P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);?KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);?KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);?KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);?KeyNumber=14;}
P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);?KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);?KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);?KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);?KeyNumber=15;}
P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);?KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);?KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);?KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);?KeyNumber=16;}
return?KeyNumber?;
}
在使用兩者結合的時候需要封裝庫的調用!(這里就凸顯了模塊化的重要行,不然你就一大堆代碼擠在一起!!!)
LCD1602顯示的調用!(注釋已寫)
調用成功后大概如下:
#include?
//引腳定義
sbit?LCD_RS=P2^6;
sbit?LCD_RW=P2^5;
sbit?LCD_E=P2^7;
#define?LCD_DataPort?P0
/**
*?@brief??LCD1602延時函數,12MHz調用可延時1ms
*?@param??無
*?@retval?無
*/
void?LCD_Delay()????????//@12.000MHz?1ms
{
unsigned?char?i,?j;
i?=?2;
j?=?239;
do
{
while?(--j);
}?while?(--i);
}
/**
*?@brief??LCD1602寫命令
*?@param??Command?要寫入的命令
*?@retval?無
*/
void?LCD_WriteCommand(unsigned?char?Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_E=1;
LCD_Delay();
LCD_E=0;
LCD_Delay();
}
/**
*?@brief??LCD1602寫數據
*?@param??Data?要寫入的數據
*?@retval?無
*/
void?LCD_WriteData(unsigned?char?Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_E=1;
LCD_Delay();
LCD_E=0;
LCD_Delay();
}
/**
*?@brief??LCD1602初始化函數
*?@param??無
*?@retval?無
*/
void?LCD_Init(void)
{
LCD_WriteCommand(0x38);
LCD_WriteCommand(0x0C);
LCD_WriteCommand(0x06);
LCD_WriteCommand(0x01);
}
/**
*?@brief??LCD1602設置光標位置
*?@param??Line?行位置,范圍:1~2
*?@param??Column?列位置,范圍:1~16
*?@retval?無
*/
void?LCD_SetCursor(unsigned?char?Line,unsigned?char?Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else
{
LCD_WriteCommand(0x80|(Column-1)+0x40);
}
}
/**
*?@brief??在LCD1602指定位置上顯示一個字符
*?@param??Line?行位置,范圍:1~2
*?@param??Column?列位置,范圍:1~16
*?@param??Char?要顯示的字符
*?@retval?無
*/
void?LCD_ShowChar(unsigned?char?Line,unsigned?char?Column,unsigned?char?Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
*?@brief??在LCD1602指定位置開始顯示所給字符串
*?@param??Line?起始行位置,范圍:1~2
*?@param??Column?起始列位置,范圍:1~16
*?@param??String?要顯示的字符串
*?@retval?無
*/
void?LCD_ShowString(unsigned?char?Line,unsigned?char?Column,unsigned?char?*String)
{
unsigned?char?i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
*?@brief??返回值=X的Y次方
*/
int?LCD_Pow(int?X,int?Y)
{
unsigned?char?i;
int?Result=1;
for(i=0;i { Result*=X; } return?Result; } /** *?@brief??在LCD1602指定位置開始顯示所給數字 *?@param??Line?起始行位置,范圍:1~2 *?@param??Column?起始列位置,范圍:1~16 *?@param??Number?要顯示的數字,范圍:0~65535 *?@param??Length?要顯示數字的長度,范圍:1~5 *?@retval?無 */ void?LCD_ShowNum(unsigned?char?Line,unsigned?char?Column,unsigned?int?Number,unsigned?char?Length) { unsigned?char?i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData('0'+Number/LCD_Pow(10,i-1)%10); } } /** *?@brief??在LCD1602指定位置開始以有符號十進制顯示所給數字 *?@param??Line?起始行位置,范圍:1~2 *?@param??Column?起始列位置,范圍:1~16 *?@param??Number?要顯示的數字,范圍:-32768~32767 *?@param??Length?要顯示數字的長度,范圍:1~5 *?@retval?無 */ void?LCD_ShowSignedNum(unsigned?char?Line,unsigned?char?Column,int?Number,unsigned?char?Length) { unsigned?char?i; unsigned?int?Number1; LCD_SetCursor(Line,Column); if(Number>=0) { LCD_WriteData('+'); Number1=Number; } else { LCD_WriteData('-'); Number1=-Number; } for(i=Length;i>0;i--) { LCD_WriteData('0'+Number1/LCD_Pow(10,i-1)%10); } } /** *?@brief??在LCD1602指定位置開始以十六進制顯示所給數字 *?@param??Line?起始行位置,范圍:1~2 *?@param??Column?起始列位置,范圍:1~16 *?@param??Number?要顯示的數字,范圍:0~0xFFFF *?@param??Length?要顯示數字的長度,范圍:1~4 *?@retval?無 */ void?LCD_ShowHexNum(unsigned?char?Line,unsigned?char?Column,unsigned?int?Number,unsigned?char?Length) { unsigned?char?i; unsigned?char?SingleNumber; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { SingleNumber=Number/LCD_Pow(16,i-1)%16; if(SingleNumber<10) { LCD_WriteData('0'+SingleNumber); } else { LCD_WriteData('A'+SingleNumber-10); } } } /** *?@brief??在LCD1602指定位置開始以二進制顯示所給數字 *?@param??Line?起始行位置,范圍:1~2 *?@param??Column?起始列位置,范圍:1~16 *?@param??Number?要顯示的數字,范圍:0~1111?1111?1111?1111 *?@param??Length?要顯示數字的長度,范圍:1~16 *?@retval?無 */ void?LCD_ShowBinNum(unsigned?char?Line,unsigned?char?Column,unsigned?int?Number,unsigned?char?Length) { unsigned?char?i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData('0'+Number/LCD_Pow(2,i-1)%2); } } 延遲函數的寫法!! #ifndef?__MATRIXKEY__H__ #define??__MATRIXKEY__H__ unsigned?char?Matrixkey(); #endif 封裝如下! 單片機 勾選這一步十分重要不然下面的項目沒辦法調用! 需要將文件Browse information 將他勾選進去,不然你的程序馬上就報錯!! 實現動態密碼鎖!! #include? #include?"LCD1602.h" #include?"Delay.h" #include?"MatrixKey.h" unsigned?char?KeyNum; //unsigned?int??Password; unsigned?int?Password?,count; void?main() { LCD_Init();?????????????????????//LCD初始化 //LCD_ShowChar(1,1,'A');????????????//在1行1列顯示字符A LCD_ShowString(1,1,"Password"); while(1) { KeyNum=Matrixkey(); if(KeyNum){ if(KeyNum<=10)??//如果S1~S10按鍵按下,輸入密碼 { if(count<4){//如果輸入次數小于四次 Password*=10;?//密碼左移一位 Password+=KeyNum%10;//獲取一位密碼 count++;?//計次加1 } } LCD_ShowNum(2,1,Password,4);?//更新顯示器 } if(KeyNum==11)??//他就是確定鍵 { if(Password==2345){ LCD_ShowString(1,14,"OK?"); Password=0; count=0; LCD_ShowNum(2,1,Password,4); } else?{?//否則 LCD_ShowString(1,14,"ERR"); Password=0; count=0; LCD_ShowNum(2,1,Password,4); } } if(KeyNum==12)?{ Password=0;??//密碼清零 count=0;??//計次清零 LCD_ShowNum(2,1,Password,4);?//更新顯示 //如果S12按鍵按下,取消 } } } 定時器 ?定時器介紹:51單片機的定時器屬于單片機的內部資源,其電路的連接和運轉均在單片機內部完成 ?定時器作用: (1)用于計時系統,可實現軟件計時,或者使程序每隔一固定時間完成一項操作 (2)替代長時間的Delay,提高CPU的運行效率和處理速度 (3) 你STC拆下,光剩下一個單片機他也能正常運行。他是在內部運行的,不影響! ?定時器個數:3個(T0、T1、T2),T0和T1與傳統的51單片機兼容,T2是此型號單片機增加的資源 ?注意:定時器的資源和單片機的型號是關聯在一起的,不同的型號可能會有不同的定時器個數和操作方式,但一般來說,T0和T1的操作方式是所有51單片機所共有的 其實定時器就像一個小鬧鐘,每隔一個時間段,計數單元的值就回加+1,當計數到達設置的鬧鐘提醒時間時,技術單元就會像中斷系統發生中斷信號,產生所謂的鬧鐘提醒! 上圖比較好理解! 實現一個項目:用按鍵控制LED流水燈模式和定時器時鐘! 這個計時器的時間范圍是————0~65535,基本上每隔一秒+1,總共定時為:65535us, 64535離計數器溢出差值1000,所以時間為1MS; 驗證一下:123———123/100=1; 123%100=23; 65毫秒 中斷器調用! #include? /** *@brief????¨ê±?÷03?ê??ˉ??1oá??@12.000khz *@param????T *@retval???T */ void?Timer0Init(void){ //TMOD=0X01;??//0000?0001 TMOD=TMOD&0xF0;?//?°?tmodμ?μú??????á?£???????±£3?2?±?£? TMOD=TMOD|0X01;?//tmodμ?×?μí????1£???????±£3?2?±?£? TF0=0; TR0=1; TH0=0x18; TL0=0xFC; ET0=1; EA=1; PT0=0; } C 語言 C++ Windows 單片機
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。