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

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

1.IAR工程文件基本配置

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

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();
在这里插入图片描述
LCD_Desk2();
在这里插入图片描述
LCD_Desk3();
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
学习一种模块,有很多种方法,其中一种方式是先去弄明白怎么使用这个模块,亲自体验了这个模块的大体功能之后,再回过头来了解该模块的工作原理,再去深层次的研究该模块。 在这里,着重介绍怎么用程序实现RC522模块的一些功能,而RC522的结构,功能等便不再介绍。 这个程序的讲解是基于MSP430F149/169单片机的。 模块使用的是SPI接口,与单片机接口如下: #define RF_LPCTL BIT3 // P2.3 射频卡休眠控制------RST #define RF_SS BIT7 // p2.7 射频卡从机选择(SS)---SDA #define RF_SCLK BIT6 // p2.6 射频卡数据时钟输出(SCLK) #define RF_DATA_OUT BIT5 // p2.5 射频卡数据输出(MOSI) #define RF_DATA_IN BIT1 // p2.1 射频模块输入(MISO) 要想对模块内部的数据块进行读写,需要完成4个步骤:寻卡→防冲突→选卡→读/写卡; 第一步:寻卡。 status2=PcdRequest(0x52,Temp);////寻卡 参数Temp为返回的卡类型 if(status2== MI_OK) { tochar(Temp[0]); tochar(Temp[1]);//输出卡类型 } 其中0x52代表寻天线区内全部卡。 卡类型(TagType): 0x4400 =Mifare_UltraLight 0x0400 =Mifare_One(S50) 0x0200 =Mifare_One(S70) 0x0800 =Mifare_Pro(X) 0x4403 =Mifare_DESFire 比如,当Temp[0]=04,Temp[1]=00时,卡类型为S50。 第二步:防冲突。 status2= PcdAnticoll(UID); //防冲撞处理,输出卡片序列号,4字节 if(status2==MI_OK) { PutString0("Card Id is:"); tochar(UID[0]); tochar(UID[1]); tochar(UID[2]); tochar(UID[3]); //输出卡片序列号 } 第三步:选卡。 status2= PcdSelect(UID); //选择卡片,输入卡片序列号,4字节 第四步:在读写卡之前需要先进行认证。 status2= PcdAuthState(PICC_AUTHENT1A, 1, Password_Buffer, UID); 其中四个参数分别代表:验证A密钥+块地址+扇区密码+卡序列号。 然后进行写操作: status2=PcdWrite(1,writeData);//写数据,将数组writeData中的数写入到卡中 其中第一个参数 1 代表写入的地址为块1. 或者进行读卡操作: status2 = PcdRead(1, str);//读卡 其中第一个参数 1 代表读的地址为块1. 读卡后得到的数据存放于数组str中。 至此,已将RC522的基本操作介绍了一遍,明白了以上这些函数,就可以对卡进行一些初步的操作,可以再结合程序研究一下。 如果需要进一步了解RC522的工作原理,可以到网上搜资料,网上有很多的。 相关参考设计资料链接:https://www.cirmall.com/circuit/2796
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值