欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于MSP430与RC522的RFID简单应用(2)

程序员文章站 2022-03-19 21:41:47
...

程序及相关函数解释,原作者为孙登波,感谢孙老师指导。

1.IAR工程文件基本配置

源代码编译好后,需要先设置工程下的器件类型、开发工具类型以及项目的 输出文件相关设置,因为 BSL 下载一般使用 TXT 类型的目标文件,IAREW430 软件默认并不会输出 TXT 目标代码文件。 点击界面左侧窗口的项目名称,选中后点击右键,选择“option”。
基于MSP430与RC522的RFID简单应用(2)
基于MSP430与RC522的RFID简单应用(2)
基于MSP430与RC522的RFID简单应用(2)
基于MSP430与RC522的RFID简单应用(2)
到这里,关于项目的设置工作已经完成,保存一下,下面就可以开始进
行编译生成目标文件了。

2.公交卡实现原理

1.

分为16个扇区,每个扇区为4块,每块16个字节,以块为存取单位
每个扇区有独立的一组密码及访问控制
每张卡有唯一***,为32位
具有防冲突机制,支持多卡操作
读写距离:10 cm以内(与读写器有关)
Mifare_Std 卡片的**属性取决于控制字。控制字的默认值是“FF078069”,此时
A**:不可被读出,有全部权限
B**:可被读出,没有任何权限

2.

基本流程
初始化
寻卡 (预置通信协议与通信波特率,判断是否为M1卡)
防冲撞 ( 多张进入射频范围,该机制会选择一张卡片)
选定卡片 (选择被选中的卡的***,并同时返回卡的容量代码)
验证卡片密码 (对某一扇区进行密码验证)
读卡 (读一个块)
充值
显示
充值完毕
锁定机器无法连续充值 (break)

main.c 源程序

//MSP430F149单片机 + RC522 +M1 
//实现公交卡充值功能
//作者:孙登波
*/
#include "msp430x14x.h"
#include "PIN_DEF.H"
#include "RC522.H"
#include "UART0_Func.c"
#include "ctype.h"
#include "BoardConfig.h"
#include "lcd.h"//顺序的重要性
#include "led8run.h"
#include "stdio.h"
#include "string.h"
#include "strtonum.h"

unsigned char writeData[16] = {1, 2, 3, 4, 0};
unsigned char str[16];
unsigned char UD[4],Temp[4];
unsigned char RF_Buffer[18];
unsigned char Password_Buffer[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // Mifare One 缺省密码
unsigned char money_ok[4] = {0x00, 0x00, 0x00, 0x00};                    //充值、消费数额数组
unsigned char money_ob[16] = {0x00,0x00,0x00,0x14};                 //充值、消费数额数组
unsigned char input_ncount = 0;                                          //输入数字个数统计
unsigned char Result[9];                                                 //存显示字符
unsigned char money[4] = {0x00, 0x00, 0x00, 0x00};
unsigned char money_dot[4] = {0x00, 0x00, 0x00, 0x00};
unsigned char money_inch[6], money_inch_hex[5];
unsigned char money_inch_dot[6], money_inch_hex_dot[5];
unsigned char money_i[4] = {0x00, 0x00, 0x00, 0x00}; //这个初值一定要有,否则出错
unsigned char money_i_dot[4] = {0x00, 0x00, 0x00, 0x00};
long int inputnum = 20;         //充值数值
unsigned char inputnum_dot = 0; //充值数值的小数部分的值
long int sum_dot = 0;           //充值后小数部分的额度
long int inteDec = 0;           //寄存器内部的整数部分值
long int dotDec = 0;            //寄存器内部的小数部分值

char MBRX[30];
char MBKeyTP[30];
char Event;
unsigned char DISP_MODE, i; // 编辑控件显示模式
unsigned char des_on = 0;   // DES加密标志
void Key_TP_Task(void);

//***************************************************************************//
//                 初始化主时钟: MCLK = XT1×(FLL_FACTOR+1)                  //
//***************************************************************************//
void Init_CLK(void)
{
  unsigned int qq;
  WDTCTL = WDTPW + WDTHOLD; // 关看门狗
  BCSCTL1 &= ~XT2OFF;       //打开XT2高速晶体振荡器
  do
  {
    IFG1 &= ~OFIFG; //Clear oscFault flag清除振荡器失效标志
    for (qq = 0xff; qq > 0; qq--)
      ;
  } while ((IFG1 & OFIFG)); //oscFault flag still set

  BCSCTL2 |= SELM_2; //MCLK=XT2
  //BCSCTL2 |= DIVM_0;        //控制MCLK不分频,默认

  BCSCTL2 |= SELS; //SMCLK=XT2
  //BCSCTL2 |= DIVS_0;        //控制SMCLK不分频,默认
}

void Delay(unsigned int time)
{
  unsigned int i, k;
  for (i = 0; i < 255; i++)
    for (k = 0; k < time; k++)
      _NOP();
}
//***************************************************************************//
//                //十进制数转为字符串               //
//***************************************************************************//
void Int_char(long int datas)
{
  if (datas / 1000000)
  {
    Result[0] = datas / 1000000 + '0';
    Result[1] = datas % 1000000 / 100000 + '0';
    Result[2] = datas % 100000 / 10000 + '0';
    Result[3] = datas % 10000 / 1000 + '0';
    Result[4] = datas % 1000 / 100 + '0';
    Result[5] = datas % 100 / 10 + '0';
    Result[6] = datas % 10 + '0';
    Result[7] = '\0';
  }
  else if (datas / 100000)
  {
    Result[0] = datas / 100000 + '0';
    Result[1] = datas % 100000 / 10000 + '0';
    Result[2] = datas % 10000 / 1000 + '0';
    Result[3] = datas % 1000 / 100 + '0';
    Result[4] = datas % 100 / 10 + '0';
    Result[5] = datas % 10 + '0';
    ;
    Result[6] = '\0';
    Result[7] = 0;
  }
  else if (datas / 10000)
  {
    Result[0] = datas / 10000 + '0';
    Result[1] = datas % 10000 / 1000 + '0';
    Result[2] = datas % 1000 / 100 + '0';
    Result[3] = datas % 100 / 10 + '0';
    Result[4] = datas % 10 + '0';
    Result[5] = '\0';
    Result[6] = 0;
    Result[7] = 0;
  }
  else if (datas / 1000)
  {
    Result[0] = datas / 1000 + '0';
    Result[1] = datas % 1000 / 100 + '0';
    Result[2] = datas % 100 / 10 + '0';
    Result[3] = datas % 10 + '0';
    Result[4] = '\0';
    Result[5] = 0;
    Result[6] = 0;
    Result[7] = 0;
  }
  else if (datas / 100)
  {
    Result[0] = datas / 100 + '0';
    Result[1] = datas % 100 / 10 + '0';
    Result[2] = datas % 10 + '0';
    Result[3] = '\0';
    Result[4] = 0;
    Result[5] = 0;
    Result[6] = 0;
    Result[7] = 0;
  }
  else if (datas / 10)
  {
    Result[0] = datas / 10 + '0';
    Result[1] = datas % 10 + '0';
    Result[2] = '\0';
    Result[3] = 0;
    Result[4] = 0;
    Result[5] = 0;
    Result[6] = 0;
    Result[7] = 0;
  }
  else
  {
    Result[0] = datas % 10 + '0';
    Result[1] = '\0';
    Result[2] = 0;
    Result[3] = 0;
    Result[4] = 0;
    Result[5] = 0;
    Result[6] = 0;
    Result[7] = 0;
  }
}
/************************************************
新增函数名称:incharg
功       能:实现充值功能
参      数:
返回值:    
/***********************************************/
char incharg(void)
{
  unsigned char g_ucTempbuf[20];
  unsigned char num;
  unsigned char temp1[10];
  unsigned char temp2[5];
  unsigned char status2;
  long int sum = 0;               //充值后整数部分的额度
  long int re;

  temp1[0] = '\0';
  temp2[0] = '\0';
  memset(money, 0, sizeof(money)); //清空钱包临时数组
  status2 = PcdRead(1, g_ucTempbuf);//读块2部分
  if (status2 == MI_OK)
  {
    for (num = 0; num < 2; num++)
    {
      money[num] = g_ucTempbuf[1 - num];//存储芯片寄存器读出来的内容,并且调换高低位(因为存储的时候,按照低位在前的顺序)
    }
    itoa(money[0], temp1, 16);       //十六进制数值转十六进制字符串(字符串无法进行计算)
    itoa(money[1], temp2, 16);       //十六进制数值转十六进制字符串(字符串无法进行计算)
    strcat(temp1, temp2);            //将两个char类型连接。输出temp1=temp1temp2
    inteDec = str_dec(temp1);        //余额整数 十六进制字符串转十进制数
    temp1[0] = '\0';                 // 字符常量占一个字节的内存空间
    temp2[0] = '\0';                 // 字符常量占一个字节的内存空间
    memset(money, 0, sizeof(money)); //将money中当前位置后面清零 。
    sum = inputnum + inteDec; //充值后余额整数部分之和
    re = sum;
    Int_char(re);            //十进制转字符串
    led();                   //led灯亮
    LCD_clear();             //清屏
    LCD_Desk2();             //lcd显示正在充值
    while (Result[i] != '\0')
    {
     LCD_write_str(Result); //lcd显示10进制字符串
     i++;
    }
    delay_ms(1800);
  }
    if(sum<65536)              //将充值完毕的余额总数再次存储到寄存器内。
  {
    itoa(sum,money_inch_hex,16); 		 //10进制数值转为16进制字符串,整数部分
    i=strlen(money_inch_hex);
    switch(i)
    {
    case 0:
      for(num=0;num<4;num++)
      {	
        money_inch_hex[num]='0';
      }
      money_inch_hex[4]='\0';
      break;
    case 1:
      money_inch_hex[4]='\0';
      money_inch_hex[3]=money_inch_hex[0];
      money_inch_hex[2]='0';
      money_inch_hex[1]='0';
      money_inch_hex[0]='0';
      break;
    case 2:
      money_inch_hex[4]='\0';
      money_inch_hex[3]=money_inch_hex[1];
      money_inch_hex[2]=money_inch_hex[0];
      money_inch_hex[1]='0';
      money_inch_hex[0]='0';
      break;
    case 3:
      money_inch_hex[4]='\0';
      money_inch_hex[3]=money_inch_hex[2];
      money_inch_hex[2]=money_inch_hex[1];
      money_inch_hex[1]=money_inch_hex[0];
      money_inch_hex[0]='0';
      break;
    }
    StringToHex(money_i, money_inch_hex);	  //16进制字符串转为16进制字节数组
    for(num=0;num<2;num++)    	   //置高位在前
    {
      money_ok[num]=money_i[1-num];
    }
  }
    return status2;  //返回判断值
}
/*******************************************
函数名称:Init_Port
功    能:初始化端口
参    数:无
返回值  :无
********************************************/
void Init_Port(void)
{
  P4DIR = RF_LPCTL + RF_SS + RF_SCLK + RF_DATA_OUT;
  P2DIR |= BIT0 + RF_LPCTL + RF_SS + RF_SCLK + RF_DATA_OUT;
  P1DIR = RF_LPCTL + RF_SS + RF_SCLK + RF_DATA_OUT;
}
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD; // 关看门狗
  int i = 0;
   unsigned char status;
   
   BoardConfig(0xf0);
  Init_Port();
  InitUART();
  Port_init();   //系统初始化,设置IO口属性
  delay_ms(100); //延时100ms
  LCD_init();    //液晶参数初始化设置
  LCD_clear();   //清屏
  LCD_Desk1();
  _EINT();
  PcdReset();     //复位RC522
  PcdAntennaOn(); //开启天线发射
  while (1)
  {  status = PcdRequest(PICC_REQIDL, Temp); ////寻卡,输出为卡类型
    if (status == MI_OK)
      status = PcdAnticoll(UD); //防冲撞处理,输出卡片***,4字节
    if (status == MI_OK)
      status = PcdSelect(UD); //选择卡片,输入卡片***,4字节
    if (status == MI_OK)
      status = PcdAuthState(PICC_AUTHENT1A, 1, Password_Buffer, UD); //在进行读写操作之前需要先进行认证
    if (status == MI_OK)
      status == incharg();//读
    if (status == MI_OK)
    {
      status = PcdWrite(1,money_ok);//充钱
      memset(money_ok,0,sizeof(money_ok));
      break;
     }
    }
      LCD_clear(); //清屏
      LCD_Desk3();  
      led();
  }
3.

存储在寄存器内部的数据格式是:十六进制数值
需要实现十六进制数值和十六进制字符串的互相转换
十六进制的字符串需要转换成十进制的数值进行计算
显示在LCD屏幕之前十进制数值又需要转换成十进制字符串
连续刷卡导致多充钱 (break 解决)

strtonum.h 源文件(进制转换操作)

/********************************************************************
//实现寄存器内数值类型转换函数
//itoa  十六进制数值转(16进制)字符串
//str_dec    十六进制字符串转为十进制数
//StringToHex  十六进制字符串转十六进制字节数组,要求字符串偶数个
//调试环境:IAR + MSP430F149 +RC522
//作者:孙登波
********************************************************************/
//
//新增函数名称:itoa
//功       能:十六进制数值转(16进制)字符串
//参      数:
//返回值:    str( 16进制)字符串
//
unsigned char *itoa(uint num, uchar *str, int radix) //十六进制数值转(16进制)字符串
{
  uchar string[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  uchar *ptr = str;
  int i;
  int j;
  if (num == 0)
  {
    str[0] = '0';
    str[1] = '0';
    str[2] = '\0';
  }
  while (num)
  {
    *ptr++ = string[num % radix];
    num /= radix;

    if (num < radix)
    {
      *ptr++ = string[num];
      *ptr = '\0';
      break;
    }
  }
  j = ptr - str - 1;
  for (i = 0; i < (ptr - str) / 2; i++)
  {
    int temp = str[i];
    str[i] = str[j];
    str[j--] = temp;
  }
  return str;
}

/************************************************
新增函数名称:str_dec
功       能:十六进制字符串转为十进制数
参      数:uchar s[]
返回值:    temp十进制数
/***********************************************/
long int str_dec(uchar s[]) //十六进制字符串转为十进制数
{
  uchar i, m, n;
  long int temp = 0;
  m = 4; //十六进制是按字符串传进来的,所以要获得他的长度
  for (i = 0; i < m; i++)
  {
    if (s[i] >= 'A' && s[i] <= 'F') //十六进制还要判断他是不是在A-F或者a-f之间a=10。。
      n = s[i] - 'A' + 10;
    else if (s[i] >= 'a' && s[i] <= 'f')
      n = s[i] - 'a' + 10;
    else
      n = s[i] - '0';
    temp = temp * 16 + n;
  }
  return temp;
}
/************************************************
新增函数名称:StringToHex
功       能:十六进制字符串转十六进制字节数组,要求字符串偶数个
参      数:uchar* hex, uchar* str
返回值:    hex
/***********************************************/
void StringToHex(uchar *hex, uchar *str) //十六进制字符串转十六进制字节数组,要求字符串偶数个
{
  int len = strlen(str); //计数器,计算str长度?
  int tmp, i;
  for (i = 0; i < len / 2; i++)
  {
    if (str[2 * i] >= '0' && str[2 * i] <= '9')
    {
      tmp = ((str[2 * i] - '0') << 4);
    }
    else if (str[2 * i] >= 'A' && str[2 * i] <= 'F')
    {
      tmp = (((str[2 * i] - 'A') + 10) << 4);
    }
    else if (str[2 * i] >= 'a' && str[2 * i] <= 'f')
    {
      tmp = (((str[2 * i] - 'a') + 10) << 4);
    }

    if (str[2 * i + 1] >= '0' && str[2 * i + 1] <= '9')
    {
      hex[i] = tmp + (str[2 * i + 1] - '0');
    }
    else if (str[2 * i + 1] >= 'A' && str[2 * i + 1] <= 'F')
    {
      hex[i] = tmp + (str[2 * i + 1] - 'A') + 10;
    }
    else if (str[2 * i + 1] >= 'a' && str[2 * i + 1] <= 'f')
    {
      hex[i] = tmp + (str[2 * i + 1] - 'a') + 10;
    }
  }
}
4.

十进制数转为字符串 的原因:
方便LCD屏幕12864的显示
通过字符串的形式,利用例程自带的字库,实现变量的动态输出。
lcd.h文件


/********************************************************************
//DM430-L型系统板控制带字库型12864液晶模块显示测试程序,显示汉字字符
//显示模式为汉字模式,直接将12864插入12864接口即可,朝外,液晶接口位于主板上方
//请注意安装位置,左边有字符说明,为靠近1602接口的1X20座子
//注意选择液晶的电源,位于电位器附近,可选5V或3.3V,根据液晶电压进行选择,默认5V
//调试环境:IAR + MSP430F149 +RC522
//小昭改写
//时间:2019.12.19
********************************************************************/

#include <msp430x14x.h>
#include "Config.h"
//*************************************************************************
//			初始化IO口子程序
//*************************************************************************
void Port_init()
{

  P4SEL = 0x00;
  P4DIR = 0xFF;
  P5SEL = 0x00;
  P5DIR |= BIT0 + BIT1 + BIT5 + BIT6 + BIT7;
  PSB_SET; //液晶并口方式
  RST_SET;
}

//***********************************************************************
//	显示屏命令写入函数
//***********************************************************************
void LCD_write_com(unsigned char com)
{
  RS_CLR;
  RW_CLR;
  EN_SET;
  DataPort = com;
  delay_ms(5);
  EN_CLR;
}

//***********************************************************************
//	显示屏数据写入函数
//***********************************************************************
void LCD_write_data(unsigned char data)
{
  RS_SET;
  RW_CLR;
  EN_SET;
  DataPort = data;
  delay_ms(5);
  EN_CLR;
}

//***********************************************************************
//	显示屏清空显示
//***********************************************************************

void LCD_clear(void)
{
  LCD_write_com(0x01);
  delay_ms(5);
}

//***********************************************************************
//函数名称:DisplayCgrom(uchar hz)显示CGROM里的汉字
//***********************************************************************
void DisplayCgrom(uchar addr, uchar *hz)
{
  LCD_write_com(addr);
  delay_ms(5);
  while (*hz != '\0')
  {
    LCD_write_data(*hz);
    hz++;
    delay_ms(5);
  }
}

//***********************************************************************
//	显示屏单字符写入函数
//***********************************************************************
void LCD_write_char(unsigned char data)
{
  LCD_write_com(0x98); //第三行显示
  delay_ms(1);
  LCD_write_data(data);
  delay_ms(1);
}
//***********************************************************************
//	显示屏单字符写入函数2
//***********************************************************************
//***********************************************************************
//	显示屏字符串写入函数
//***********************************************************************
void LCD_write_str(unsigned char *s)
{

  LCD_write_com(0x98); //第三行显示 显示余额
  delay_ms(2);
  while (*s)
  {
    LCD_write_data(*s);
    delay_ms(2);
    s++;
  }
}
//****************************************************************
//函数名称:Display()显示测试结果
//****************************************************************
//void Display(void)
//{
  //DisplayCgrom(0x80, "欣世纪电子欢迎你");
  //DisplayCgrom(0x88, "旺:jingyehanxing");
  //DisplayCgrom(0x90, "www.avrgcc.com  ");
  //DisplayCgrom(0x98, "电话057487470625");
//}

//***********************************************************************
//	显示屏初始化函数
//***********************************************************************
void LCD_init(void)
{
  LCD_write_com(FUN_MODE); //显示模式设置
  delay_ms(5);
  LCD_write_com(FUN_MODE); //显示模式设置
  delay_ms(5);
  LCD_write_com(CURSE_DIR); //显示模式设置
  delay_ms(5);
  LCD_write_com(DISPLAY_ON); //显示开
  delay_ms(5);
  LCD_write_com(CLEAR_SCREEN); //清屏
  delay_ms(5);
}
//***********************************************************************
//    液晶显示界面欢迎
//***********************************************************************
void LCD_Desk1(void)
{
  LCD_clear();
  DisplayCgrom(0x80, "小昭");
  DisplayCgrom(0x90, "欢迎您");
  DisplayCgrom(0x88, "单次充值20元");
  DisplayCgrom(0x98, "未完成请勿拿走卡");
   delay_ms(20);
}
//***********************************************************************
//      液晶显示界面正在充值
//***********************************************************************
void LCD_Desk2(void)
{
  LCD_clear();
  DisplayCgrom(0x80, "请勿移动卡片");
  DisplayCgrom(0x90, "正在充值20元");
  DisplayCgrom(0x88, "充值完成余额:");
     delay_ms(20);
}
//***********************************************************************
//      液晶显示界面充值完成
//***********************************************************************
void LCD_Desk3(void)
{
  LCD_clear();
  DisplayCgrom(0x80, "╭∞━━╮");
  DisplayCgrom(0x90, "┃●  ● ┃");
  DisplayCgrom(0x88, "┃  ε   ┃");
  DisplayCgrom(0x98, "○━━━╯");
     delay_ms(20);
}
//***********************************************************************
//      液晶显示界面充值完成
//***********************************************************************
void LCD_Desk(void)
{
  LCD_clear();
  DisplayCgrom(0x80, "公交公司欢迎您");
  DisplayCgrom(0x90, "正在充值20元");
  DisplayCgrom(0x88, "充值完成余额:");
     delay_ms(20);
}

注意:
显示扣款后余额:

sum = inteDec – inputnum ;

显示充值后余额:

um = inputnum + inteDec; //充值后余额整数部分之和
 re = sum;
 Int_char(re);                                //十进制数转为字符串               //
 led();
 LCD_clear();   //清屏
 LCD_Desk2();
 while (Result[i] != ‘\0)               //Result[i]为转出来的字符串
 {
   LCD_write_str(Result); //显示10进制字符串
   i++;
  }
 delay_ms(1800);
 }

3.实验结果

LCD_Desk1();
基于MSP430与RC522的RFID简单应用(2)
LCD_Desk2();
基于MSP430与RC522的RFID简单应用(2)
LCD_Desk3();
基于MSP430与RC522的RFID简单应用(2)

相关标签: 实验