51單片機驅動FM1702實現讀寫卡的資料包分享:
0.png (36.78 KB, 下載次數: 57)
下載附件
2018-11-6 01:52 上傳
FM1702天線設計與電路設計及編程指南等:
0.png (7.42 KB, 下載次數: 53)
下載附件
2018-11-6 01:52 上傳
程序使用說明:
1.程序用到的數碼管、FM1702、按鍵的所有引腳均有定義,如果用戶按照這個定義,程序上電后應該是數 碼管無顯示內容。
2.當有卡片靠近后,數碼管先顯示卡號序列號的高兩位,顯示大約2秒,然后讀取卡片的塊8的數值并顯示
顯示時間大約為6秒
3.按鍵是雙功能鍵。按鍵2和3是充值和刷卡鍵,4是確認鍵,只有先按2或者3然后按4,否則直接按4程序 不會反應。當按了4后,此時按鍵2和3就變成增值或者減值按鍵,同時短按一下是增1或者減1,長按是 增10或者減10.確認了數值后,再次按4鍵,程序會根據你按得是充值鍵還是刷卡鍵進行響應的加或減運 算,并將運算后得值寫入塊8,然后再次讀取,并顯示在數碼管上。在你按鍵確認數值之前,數碼管會 顯示當前你的按鍵值是多少。
4.總結使用流程就是:放卡到讀卡器—按動2或3鍵—按4—再按2或3(長按短按效果不一樣,數碼管會顯 示)—再按4—卡拿開
不足之處:
1.沒有用到芯片自帶的E2PROM,所以程序沒有它的讀寫程序。
2.沒有用到卡的自增自減運算函數,這個涉及卡的控制字符,卡的資料有詳細,所以也沒寫
3.防衝突沒有實現那種公平的防衝突,此程序實現的是隨機選卡
注意事項:
網上關于射頻卡的資料很多關鍵的地方都沒有說明,類似SPI時序,寄存器讀寫指令,FIFO讀寫時間等等,所以下列幾點一定要注意,這是我在做這個時遇到的問題。
1.首先,spi時序,注意讀時和寫時的sck,以及左移函數的位置,很重要。也可以把SPI的讀和寫分開寫 ,會的自己試一下。
2.1702的寄存器讀寫并不是單純的把寄存器地址寫進去,而是有一定規則的。不論讀寫,寄存器都是先左 移一位,即有效的六位地址(做的時候你就明白為什麼是六位)處于一個字節的中間,最低位不論讀寫 都為0,高位當讀時是1,寫時是0,這點非常重要,查遍所有資料,都沒有這點。
3.1702初始化時,按照pdf所給的啟動步驟來,當時我覺得最后一條轉換線性尋址好像沒用到,所以沒寫 ,結果怎麼也不好使,后來一加,什麼都好使了。這也是很關鍵的一點。
4.延時問題,當FIFO有數據要發送或者接受時,啟動0x1e命令后,根據FIFO字節數要加適當延時,這是很 關鍵的點,具體參考程序。
大致就這些了,程序實現的功能比較簡單,后續我也許會加上12864,做成一個界面化的帶密碼修改,以及卡的識別的小型一卡通系統,類似于學校那種什麼飯卡、交通、圖書館、水卡的東西,如果做的話,我會把后續的傳上來。敬請期待....
51單片機源程序如下:
- #include<reg52.h>
- #include<intrins.h>
- #include<FM1702.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar Fbuff[16]; //發送FIFO緩存
- uchar Jbuff[16]; //接收FIFO緩存
- uchar UID[7]; //卡型及卡號
- uchar Data[4]; //按鍵值存儲區
- uchar code seg[16]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E}; //數碼管段選對應0~f
- uchar count=0 ; //按鍵回傳的值
- uchar shuaka,chongzhi,keyflag=0;
- sbit k2=P3^5; //充值‘加值鍵(實現加1或者加10)
- sbit k3=P3^2; //刷卡’減值鍵(實現減1或者減10)
- sbit k4=P3^3; //確認鍵
- sbit nWR=P2^4; //74hc373片選
- /*****************1702函數聲明**************************/
- uchar spi(uchar m);
- void fifo_clear();
- void resig_write(uchar reg,uchar da);
- uchar resig_read(uchar reg);
- uchar fifo_read(uchar count,uchar *s);
- void fifo_write(uchar count,uchar *s);
- uchar inti_1702();
- void card_halt();
- uchar request();
- uchar card_anticoll();
- uchar card_select();
- uchar card_authtication(uchar m) ;
- uchar card_read(uchar m);
- uchar card_write(uchar m);
- uchar loadkey();
- void delay(uchar m);
- /********************按鍵顯示函數聲明***************/
- void display();
- void keyscan() ;
- void data1deal() ;
- void data2deal(uchar m);
- void lcdclear();
- /***********************子函數解釋******************/
- /*********************************************************/
- //解釋: 這是spi總線的讀寫時序,所有的寄存器操作基于此時序,非常重要
- //
- //
- //輸入:要寫入的16進制參數
- //
- //
- //輸出:內部傳回的16進制參數
- //
- /********************************************************/
- uchar spi(uchar m)
- {
- uchar i,temp=0;
- for(i=0;i<8;i++)
- {
- sck=0;
- if(m&0x80)
- mosi=1;
- else
- mosi=0;
- m<<=1;
- sck=1;
- temp<<=1;
- if(miso)
- temp|=0x01;
- }
- sck=0;
- mosi=0;
- return temp;
- }
- /*********************************************************/
- //解釋:寫寄存器函數
- //
- //
- //輸入:寄存器地址 以及要寫入的參數
- //
- //
- //輸出:
- //
- //注意。≡谒械馁Y料中都沒有給出寄存器尋址時的格式,下邊的有,看仔細了,如果連寄存器都找不到,后邊的就不用看了
- /********************************************************/
- void resig_write(uchar reg,uchar da)
- {
- sck=0;
- reg<<=1;
- cs=0;
- reg=reg&0x7e;
- spi(reg);
- spi(da);
- cs=1;
- }
- /*********************************************************/
- //解釋:讀寄存器函數
- //
- //
- //輸入:寄存器地址
- //
- //
- //輸出:該寄存器目前的值
- //
- //注意!!讀寫寄存器時指令不一樣,仔細看。
- /********************************************************/
- uchar resig_read(uchar reg)
- {
- uchar temp;
- sck=0;
- _nop_();
- _nop_();
- cs=0;
- reg<<=1;
- reg|=0x80;
- spi(reg);
- temp=spi(0x00);
- cs=1;
- return temp;
-
- }
- /*********************************************************/
- //解釋:FIFO緩衝器的讀函數
- //
- //
- //輸入:讀取的字節個數 ,返回的值存放首地址
- //
- //
- //輸出:讀成功的話會返回真值,否則返回0
- //
- //
- /********************************************************/
- uchar fifo_read(uchar count,uchar *s)
- {
- uchar i,temp;
- temp=resig_read(FIFOLength);
- if(temp<count)
- return 0;
- else
- {
- for(i=0;i<count;i++)
- {
- temp=resig_read(FIFODaTa);
- *(s+i)=temp;
- }
- }
- return 1;
- }
- /*********************************************************/
- //解釋:FIFO緩衝器的寫函數
- //
- //
- //輸入:寫入的字節個數 ,要寫入的值的存放首地址
- //
- //
- //輸出:
- //
- //
- /********************************************************/
- void fifo_write(uchar count,uchar *s)
- {
- uchar i,temp;
- for(i=0;i<count;i++)
- {
- temp=*(s+i);
- resig_write(FIFODaTa,temp);
- }
- }
- /*********************************************************/
- //解釋:芯片FM1702初始化函數
- //
- //
- //輸入:
- //
- //
- //輸出:初始化成功的話返回真值,否則返回0
- //
- //
- //注意:初始化步驟非常重要,一定要按照使用手冊的啟動步驟來,參考所給pdf
- /********************************************************/
- uchar inti_1702()
- {
- uchar temp,i;
- FM1702rst=1;
- mosi=1;
- sck=1;
- delay(20);
- FM1702rst=0;
- delay(20);
- while(resig_read(Command));
- resig_write(0x00,0x80);
- temp=resig_read(Command);
- while(temp);
- resig_write(0x00,0x00); //切換到線性尋址(此命令非常重要,否則無法啟動發送 )
- resig_write(TimerClock,0x0b); //address 2AH /* 定時器週期設置寄存器 */
- resig_write(TimerControl,0x02); //address 2BH /* 定時器控制寄存器 */
- resig_write(TimerReload,0x42); //address 2CH /* 定時器初值寄存器 */
- resig_write(InterruptEn,0x7f); //address 06H /* 中斷使能/禁止寄存器 */
- resig_write(InterruptRq,0x7f); //address 07H /* 中斷請求標識寄存器 */
- resig_write(MFOUTSelect,0x02); //address 26H /* mf OUT 選擇配置寄存器 */
- resig_write(TxControl,0x5b); //address 11H /* 發送控制寄存器 */
- resig_write(RxControl2,0x01);
- resig_write(RxWait,0x07);
- for(i=0;i<16;i++)
- {
- Fbuff[i]=0;
- Jbuff[i]=0;
- }
- lcdclear() ;
- if(temp==0x00)
- return 1;
- else
- return 0;
- }
- /*********************************************************/
- //解釋:延時函數,單次延時為5ms
- //
- //
- //輸入:要延時的次數
- //
- //
- //輸出:
- //
- //
- /********************************************************/
- void delay(uchar m) //單次定時為10ms
- {
- TMOD=0x01;
- while(m--)
- {
- TH0=0xfe;
- TL0=0x33 ;
- TR0=1;
- while(!TF0);
- TF0=0;
- TR0=0;
- }
-
- }
- /*********************************************************/
- //解釋:卡的回應函數,判斷是否有卡在讀寫器跟前
- //
- //
- //輸入:
- //
- //
- //輸出:如果有卡在的話返回真值,否則返回0
- //
- //
- /********************************************************/
- uchar request()
- {
- uchar temp;
- resig_write(CRCResultLSB,0x63);
- resig_write(CWConductance,0x3f);
- resig_write(BitFraming,0x07);
- resig_write(ChannelRedundancy,0x03);
- temp=resig_read(Control);
- temp=temp&0x7f;
- resig_write(Control,temp);
- resig_read(FIFOLength);
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x52;
- fifo_write(1,Fbuff);
- resig_write(Command,0x1e);
- delay(1);
- temp=resig_read(FIFOLength);
- if(temp==0x02)
- return 1;
- else
- return 0;
- }
- /*********************************************************/
- //解釋:防衝突函數 (我所做的此函數沒有手冊的那種功能,只是實現了單卡交易功能)
- //
- //
- //輸入:
- //
- //
- //輸出:防衝突成功的話返回真值,否則返回0
- //
- //實現功能:如果有多張卡在讀卡器區域,只選中一張,并讀取驗證這張卡的ID,然后存儲
- /********************************************************/
- uchar card_anticoll() //防衝突函數
- {
- uchar temp,i;
- resig_write(DecoderControl,0x28);
- resig_write(Control,0x08);
- resig_write(ChannelRedundancy,0x03);
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x93;
- Fbuff[1]=0x20;
- fifo_write(2,Fbuff);
- resig_write(Command,0x1e);
- delay(2);
- temp=resig_read(FIFOLength);
- if(temp==0x05)
- {
- temp=0;
- fifo_read(5,UID);
- delay(1);
- for(i=0;i<5;i++)
- {
- temp=temp^UID[i];
- }
- if(temp==0)
- return 1;
- else
- return 0;
- }
- else
- return 0;
- }
- /*********************************************************/
- //解釋:選卡函數
- //
- //
- //輸入:
- //
- //
- //輸出:選卡成功的話返回真值,否則返回0
- //
- //實現功能:將要交易的卡號發給卡,如果回應正確則選卡成功
- /********************************************************/
- uchar card_select()
- {
- uchar i,temp;
- resig_write(ChannelRedundancy,0x0f);
- resig_write(Control,0x08);
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x93;
- Fbuff[1]=0x70;
- for(i=0;i<5;i++)
- {
- Fbuff[i+2]=UID[i];
- }
- fifo_write(7,Fbuff);
- resig_write(Command,0x1e);
- delay(2);
- temp=resig_read(FIFOLength);
- if(temp==0x01)
- return 1 ;
- else
- return 0 ;
- }
- /*********************************************************/
- //解釋:三重認證函數
- //
- //
- //輸入:要操作的塊號
- //
- //
- //輸出:如果三重認證的話返回真值,否則返回0
- //
- //實現功能:這是卡片與讀卡器之間的默認通信協議,次程序執行成功后才可以與卡進行交易
- /********************************************************/
- uchar card_authtication(uchar m)
- {
- uchar i,temp;
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x60;
- Fbuff[1]=m;
- for(i=0;i<4;i++)
- {
- Fbuff[i+2]=UID[i];
- }
- fifo_write(6,Fbuff);
- resig_write(InterruptEn,0xa5);
- resig_write(Command,0x0c);
- delay(2);
- temp=resig_read(SecondaryStatus);
- temp=temp&0x07;
- if(temp==0)
- {
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- resig_write(InterruptEn,0xa4);
- resig_write(Command,0x14);
- delay(2);
- temp=temp=resig_read(Control);
- temp&=0x08;
- if(temp==0x08)
- return 1;
- else
- return 0;
- }
- return 0;
- }
- /*********************************************************/
- //解釋:讀卡函數
- //
- //
- //輸入:要讀的考號
- //
- //
- //輸出:讀卡成功的話返回真值,否則返回0
- //
- //實現功能:讀取指定卡號的內容,并傳送給FIFO
- /********************************************************/
- uchar card_read(uchar m)
- {
- uchar temp;
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- resig_write(ChannelRedundancy,0x0f);
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x30;
- Fbuff[1]=m;
- fifo_write(2,Fbuff);
- resig_write(Command,0x1e);
- delay(0x04);
- temp=resig_read(FIFOLength);
- if(temp==16)
- {
-
- fifo_read(16,Jbuff);
- return 1;
- }
- else
- return 0;
- }
- /*********************************************************/
- //解釋:寫卡函數
- //
- //
- //輸入:要寫入的卡號
- //
- //
- //輸出:寫卡成功的話返回真值,否則返回0
- //
- //實現功能:將發送緩衝區的數據寫入指定的塊號
- /********************************************************/
- uchar card_write(uchar m)
- {
- uchar temp;
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0xA0;
- Fbuff[1]=m;
- fifo_write(2,Fbuff);
- resig_write(Command,0x1e);
- delay(2);
- temp=resig_read(FIFOLength);
- if(temp==1)
- {
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=Jbuff[0];
- fifo_write(16,Fbuff);
- resig_write(Command,0x1e);
- delay(10);
- temp=resig_read(FIFOLength);
- if(temp==1)
- return 1;
- else
- return 0;
- }
- else
- return 0;
- }
- /*********************************************************/
- //解釋:加載密匙函數
- //
- //
- //輸入:
- //
- //
- //輸出:成功的話返回真值,否則返回0
- //
- //實現功能:建立與卡通信協議的第一步,將密匙發送給卡,驗證密匙是否成功,成功的話執行三重認證
- /********************************************************/
- uchar loadkey()
- {
- uchar temp;
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- fifo_write(12,changekey);
- resig_write(Command,0x19);
- delay(3);
- temp=resig_read(ErrorFlag);
- if(temp==0)
- return 1;
- else
- return 0;
- }
- /*********************************************************/
- //解釋:設置卡的暫停態函數
- //
- //
- //輸入:
- //
- //
- //輸出:執行成功的話返回真值,否則返回0
- //
- //實現功能:將卡設置為終止交易態,若要再次交易必須從頭重新開始認證
- /********************************************************/
- void card_halt()
- {
- uchar temp;
- resig_write(InterruptEn,0x7f);
- resig_write(InterruptRq,0x7f);
- resig_write(Command,0x00);
- temp=resig_read(Control);
- temp=temp|0x01;
- resig_write(Control,temp);
- Fbuff[0]=0x50;
- Fbuff[1]=0x00;
- fifo_write(2,Fbuff);
- resig_write(InterruptEn,0xbd);
- resig_write(Command,0x1e);
- delay(2);
- }
- /****************按鍵顯示子函數解釋********************/
- /*********************************************************/
- //解釋:卡的高兩位序列號函數
- //
- //
- //輸入:
- //
- //
- //輸出:
- //
- //實現功能:將卡的高兩位序列號處理為16進制后存放在相應顯示區
- /********************************************************/
- void data1deal() //序列號處理
- {
- uchar temp,i;
- for(i=0;i<4;i++)
- Data[i]=0;
- temp=UID[3];
- Data[1]=temp/16;
- Data[0]=temp%16;
- temp=UID[2];
- Data[3]=temp/16;
- Data[2]=temp%16;
- }
- /*********************************************************/
- //解釋:顯示數據處理函數
- //
- //
- //輸入:
- //
- //
- //輸出:
- //
- //實現功能:將要現實的數據處理為10進制后存放在相應顯示區
- /********************************************************/
- void data2deal(uchar m) //顯示數據及按鍵處理
- {
- uchar i,temp;
- for(i=0;i<4;i++)
- Data[i]=0;
- temp=m;
- Data[0]=temp%10;
- Data[1]=temp%100/10;
- Data[2]=temp/100;
- }
- /*********************************************************/
- //解釋:按鍵掃描函數
- //
- //
- //輸入:
- //
- //
- //輸出:輸出相應的交易種類以及交易數額(會在說明裡做詳細說明)
- //
- //
- /********************************************************/
- void keyscan()
- {
- if(k2==0||k3==0)
- {
- if(k2==0)
- {
- delay(100);
- if(k2==0)
- delay(250);
- if(keyflag==1)
- {
- if(k2==1)
- {
- if(count==255)
- count=0 ;
- else
- count++;
- }
- if(k2==0)
- {
- while(!k2)
- display();
- if(count>=246)
- count=count+11;
- else
- count=count+10;
- }
- }
- else
- {
- chongzhi=1;
- shuaka=0;
- }
- }
- if(k3==0)
- {
- delay(100);
- if(k3==0)
- delay(250);
- if(keyflag==1)
- {
- if(k3==1)
- {
- if(count==0)
- count=255;
- else
- count--;
- }
- if(k3==0)
- {
- while(!k3)
- display();
- if(count<=9)
- count=245+count;
- else
- count=count-10;
- }
- }
- else
- {
- shuaka=1;
- chongzhi=0;
- }
-
- }
- }
- if(k4==0)
- {
- delay(180);
- if(k4==0)
- keyflag=keyflag+1;
- }
- }
- /*********************************************************/
- //解釋:顯示函數
- //
- //
- //輸入:
- //
- //
- //輸出:
- //
- //
- /********************************************************/
- void display()
- {
- unsigned char time=0;
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=seg[Data[3]];
- WR=1;
- P2=0X0e;
- time=5000;
- while(time--);
-
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=seg[Data[2]];
- WR=1;
- P2=0X0d;
- time=5000;
- while(time--);
-
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=seg[Data[1]];
- WR=1;
- P2=0X0b;
- time=5000;
- while(time--);
-
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=seg[Data[0]];
- WR=1;
- P2=0X07;
- time=5000;
- while(time--);
-
- }
- /*********************************************************/
- //解釋:lcd清屏函數
- //
- //
- //輸入:
- //
- //
- //輸出:
- //
- /********************************************************/
- void lcdclear()
- {
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=0xff;
- WR=1;
- P2=0X0e;
-
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=0xff;
- WR=1;
- P2=0X0d;
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=0xff;
- WR=1;
- P2=0X0b;
-
- nWR=0;
- P2=0x0f;
- WR=0;
- P0=0xff;
- WR=1;
- P2=0X07;
- }
- /*****************************主函數****************************/
- void main()
- {
- uchar temp,p,i,j;
- temp=inti_1702();
- while(1)
- {
- switch(temp)
- {
- case 0: p=inti_1702();if(p) temp++;else temp=0;break;
- case 1: p=request(); if(p) {temp++;led5=~led5;}else temp=1;break;
- case 2: p=card_anticoll(); if(p){ temp++;led6=~led6;}else temp=1;break;
- case 3: p=card_select(); if(p) temp++; else temp=1;break;
- case 4: p=loadkey();if(p){temp++;led7=~led7;} else temp=1;break;
- case 5: p=card_authtication(PICC_BLOCK);if(p){ temp++;led8=~led8;}else temp=1;break;
- case 6: p=card_read(PICC_BLOCK);
- if(p)
- {
- temp++;
- data1deal();
- for(i=0;i<2;i++)
- for(j=0;j<150;j++)
- display();
- data2deal(Jbuff[0]);
- i=10;
- j=200;
- while(i--)
- {
- while(j--)
- { display();
- keyscan();
- if(shuaka||chongzhi)
- { data2deal(count);
- display();
- if(keyflag==0x02)
- {
- if(shuaka)
- Jbuff[0]=Jbuff[0]-count ;
- if(chongzhi)
- Jbuff[0]=Jbuff[0]+count;
- keyflag=0;
- shuaka=0;
- chongzhi=0;
- count=0;
- j=0;
- i=0;
- }
- else
- j=100;
- }
-
- }
- }
-
- }
- else
- temp=0;break;
- case 7: p=card_write(PICC_BLOCK);if(p){temp++;led9=~led9;} else temp=0;break;
- case 8: p=card_read(PICC_BLOCK);
- if(p)
- {
- temp++;
- data1deal();
- for(i=0;i<2;i++)
- for(j=0;j<150;j++)
- display();
- data2deal(Jbuff[0]);
- i=5;
- j=200;
- while(i--)
- {
- while(j--)
- display();
- }
- lcdclear() ;
- }
- else
- temp=0; break;
- case 9: card_halt();temp=0;break;
- default: break;
-
- }
- }
- }
復制代碼
所有資料51hei提供下載:
基於51的FM1702射頻卡.rar
(3.26 MB, 下載次數: 94)
2018-11-5 21:03 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|