Jacktang

  • 2019-02-16
  • 发表了主题帖: 多数EMI问题的产生和时钟信号有关

         随着技术的发展,数字信号的时钟频率越来越高,电路系统对于信号的建立、保持时间、时钟抖动等要素提出越来越高的要求。EMI,即电磁干扰,是指电路系统通过传导或者辐射的方式,对于周边电路系统产生的影响。EMI会引起电路性能的降低,严重的话,可能导致整个系统失效。在实际操作中,相关机构颁布电磁兼容的规范,确保上市的电子产品满足规范要求。       时钟信号常常是电路系统中频率最高和边沿最陡的信号,多数EMI问题的产生和时钟信号有关。       降低EMI的方法有许多种,包括屏蔽、滤波、隔离、铁氧体磁环、信号边沿控制以及在PCB中增加电源和GND层等等。在应用中可以灵活使用以上方法,其中屏蔽是相对简单的机械学方法,成本较高,不适用于手持和便携式设备;滤波和信号边沿控制对于低频信号有效,不适合当前广泛应用的高速信号。另外,使用EMI/RFI滤波器这些被动元器件,会增加成本;通过LAYOUT技巧降低EMI显然比较费时,而且因设计的不同,手段也不尽相同 展频时钟(Spread Spectrum Clocking)是另一种有效降低EMI的方法,本文将简要描述展频时钟发生器(Spread Spectrum Clock Generator, SSCG)是如何降低EMI的。 概述       时钟展频通过频率调制的手段将集中在窄频带范围内的能量分散到设定的宽频带范围,通过降低时钟在基频和奇次谐波频率的幅度(能量),达到降低系统电磁辐射峰值的目的。 一般数字时钟有很高的Q值,即所有能量都集中在很窄的频率范围内,表现为相对较高的能量峰值。在频谱图上容易看到在中间频率上有很高的峰值,在奇次谐波位置有较低的峰值;SSCG通过增加时钟带宽的方法降低峰值能量,减小时钟的Q值。图示意SSCG的工作原理。          时钟展频通过特定方式调制原始时钟信号。Linear和Hershey Kiss(不是好时之吻巧克力哦)是常用的调制方式。 应用特点      SSCG是一种Active且低成本的解决EMI问题的方案,可以在保证时钟信号完整性的基础上应对更广频率范围内EMI问题。相比传统上使用Ferrite Beads和RF Chokes抑制EMI,SSCG通过时钟内部集成电路调制频率的手段来达到抑制EMI峰值的目的。SSCG不仅调制时钟源,其它的同步于时钟源的数据、地址和控制信号,在时钟展频的同时也一并得以调制,整体的EMI峰值都会因此减小,所以说,时钟展频是系统级的解决方案。这是SSCG相比其它抑制EMI措施的最大优势。 SSCG功能可以由用户选择不同配置,ON或者OFF,以及不同的调制范围等。      被动的EMI抑制器件通常也会集成ESD保护功能,是不耗电的。SSCG由于使用到展频等集成电路功能,会消耗能量。

  • 发表了主题帖: PT100测温电路

    PT100测温电路

  • 发表了主题帖: 如何选择最合适的网线做POE供电使用?

          市面的非标准网线材质主要有铜包钢、铜包铝、铜包铁等,这些网线的阻值大,都不适合用来POE供电。POE IEEE 802.3af标准要求PSE输出端口的输出功率为15.4W或者15.5W, 传输100米后的PD设备接受功率必须不小于12.95W。   按照802.3af典型电流值为350ma计算,100米网线的电阻必须为(15.4-12.95W)/350ma = 7欧姆或者(15.5-12.95)/350ma = 7.29欧姆。   而标准网线是天然就满足这个要求的,因为IEEE 802.3af poe供电标准本身就是以标准网线制定的。而之所以会产生POE供电网线要求这个问题,是因为市面上的很多网线都是非标准网线,不是严格按照标准网线的要求来生产的。   一、哪种网线最适合POE供电?   POE供电必须使用无氧铜材质的网线,即标准网线。   网线必须按照568A或者568B的标准连接好网线,必须接通8根线,同时长度要求在100米内。网线的质量越好,传输稳定性就越高,至少是超五类的网线,如果预算成本足够,可以选择传输距离更远、效果更好的6类网线。   超五类线:超5类线具有衰减小,串扰少的优点,并且具有更高的衰减串扰比(ACR)和信噪比(StructuralReturnLoss)、更小的时延误差。超5类线主要用于千兆位以太网(1000Mbps)。   六类线:该类电缆的传输频率为1MHz~250MHz,六类布线系统在200MHz时综合衰减串扰比(PS-ACR)有较大的余量,它提供2倍于超五类的带宽。六类布线的传输性能远远高于超五类标准,最适用于传输速率高于1Gbps的应用。   六类与超五类的另一个重要的不同点在于:   六类线改善了在串扰以及回波损耗方面的性能,对于新一代全双工的高速网络应用而言,优良的回波损耗性能是极重要的。同时六类标准中取消了基本链路模型,布线标准采用星形的拓扑结构,要求的布线距离的永久链路长度不能超过90m,信道长度不能超过100m。   二、如何识别网线的真假?   1、看材质   2、看网线的标识   3、看手感   除了看还可以通过摸的方法来感觉真假5类/超 5类线在材料上的差别。真5类/超5类线质地比较软,这主要是为了适应不同的网络环境需求。双绞线电缆中一般使用铜线做导线芯,比较软,因为有些网络环境可能需要网线进行小角度弯折,如果线材较硬就很容易造成断路。而一些不法厂商在生产时为了降低成本,在铜中添加了其他的金属元素,做出来的导线比较硬,不易弯曲,使用中容易产生断线。   4、用刀割   用剪刀去掉一小截线外面的塑料包皮,使其露出4对芯线,观看这些芯线。真5类/超5类线4对芯线中白色的那条不应是纯白的,而是带有与之成对的那条芯线颜色的花白,这主要是为了方便用户在制作水晶头时区别线对。而假货通常是纯白色的或者花色不明显的。   另外真假5类/超5类线的4对芯线的绕线密度也有区别,真5类/超5类线绕线密度适中,方向是逆时针;假线通常密度很小,方向也可能会是顺时针(比较少),因为假线在制作方面较简单,因此工艺上较粗糙。   5、用火烧   可以将双绞线放在高温环境中测试一下,看看在35℃至40℃时,网线外面的胶皮会不会变软,真网线是不会变软的,假的就不一定了;另外真网线外面的胶具有阻燃性,而假的有些则不具有阻燃性,不符合安全标准,各位购买时不妨试试。   三、实际应用中的网线选择   目前的网线选择一般都是非屏蔽六类双绞线了,超五类网线基本不用了,在一个工程中,薛哥建议统一选择六类双绞线,除非成本控制很严格,可以选择超五类网线,但是都是国标。尤其距离比较长的网线一定要选择国标。

  • 2019-02-15
  • 发表了主题帖: fdc2214 oled电容测试msp430程序源码

    单片机源程序如下: /** ****************************************************************************** * @file    FDC2214.c * @author  BOB    * @version V1.0 * @date    2018-07-5 * @email    * @brief   FDC2214配置及数据读取函数 ****************************************************************************** **/ #include <io430.h> #include "fdc2214.h" #include "iic.h" #include "math.h" #include "Config.h" //ADDR和SD引脚初始化 #define FDC_ADDR_0                P1OUT &= ~BIT4           //FDC_ADDR置低 #define FDC_ADDR_1                P1OUT |=  BIT4           //FDC_ADDR置高 #define FDC_SD_0                    P1OUT &= ~BIT5           //FDC_SD置低 #define FDC_SD_1                    P1OUT |=  BIT5           //FDC_SD置高 /*************************************** * 函数名:ADDR_SD_Init * 描述  :配置LDC用到的I/O口                    ADDR--PC11                                    SD  --PC12 * 输入  :无 * 输出  :无 **************************************/ /* void ADDR_SD_Init(void)       //ADDR和SD引脚初始化 {                                                 } */ /*************************************** * 函数名:InitFDC2214 * 描述  :初始化FDC2214 * 输入  :无 * 输出  :retVal  0 and 1 **************************************/ u8 FDC2214_init(void) {         u16 id;         u8 retVal=1;         u8 ErrCount = 0;                  FDC_ADDR_0;// ADDR=0(FDC2214_IIC地址选择=0X2A) // ADDR=1(FDC2214_IIC地址选择=0X2B)         FDC_SD_0;  // SD=0开启输入   // SD=1关闭输入              default_addr = EVM_DEFAULT_I2CADDR;  //FDC2214地址选择暂存     delay_ms(10);                          // software reset         MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_RESET_DEVICE,0x8000);              delay_ms(10);                  do         {                 if (ErrCount++ > 50)                         {                                 return 0;                         }                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH0,0xFFFF); // 4 clock periods                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH1,0xFFFF);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH2,0xFFFF);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_REF_COUNT_CH3,0xFFFF);                                          retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_OFFSET_CH0,0x0000);    //补偿值                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_OFFSET_CH1,0x0000);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_OFFSET_CH2,0x0000);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_OFFSET_CH3,0x0000);                                          retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH0,0x0400); // 1 clock period                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH1,0x0400);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH2,0x0400);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_SETTLE_COUNT_CH3,0x0400);                                          retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH0,0x1001); // 1000                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH1,0x1001);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH2,0x1001);                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_CLOCK_DIVIDERS_CH3,0x1001);                                          retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH0,0xF800); //                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH1,0xF800); //                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH2,0xF800); //                 retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_DRIVE_CURRENT_CH3,0xF800); //                                                  retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_ERROR_CONFIG,0x0001); // report only DRDYs to INT                                                      retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_MUX_CONFIG,0xC20C); // ch0, ch1,ch2,ch3-> Wipro for 4 ch                                      retVal &= MPU_Write_2Byte(default_addr,LDC13xx16xx_CMD_CONFIG,0x1E01); // CLKIN pin1281                                          }while(retVal!=0);            //        id=MPU_Read_2Byte(default_addr,LDC13xx16xx_CMD_DEVID);//读设备ID //    if(id==0x3055||id==0x3054) //        {    //       return 1; //        } //    else //    { //      return 0; //    }              return 1; } /*************************************** * 函数名:evm_processDRDY * 描述  :读取寄存器数据 * 输入  :无 * 输出  :无 **************************************/ void evm_processDRDY(unsigned long allData[4]) {     u8 i=0;     unsigned long reading = 0;     float CAP_Data[4];     float conver = 0;   //最终的转换的结果                                   for(i=0;i<=3;i++)         {                                                         //0x0FFF  最高到只28位           reading = (unsigned long)(MPU_Read_2Byte(default_addr,i*2) & 0x0FFF) << 16;           reading |= MPU_Read_2Byte(default_addr,(i*2)+1);           allData=reading;           //CAP_Data=reading;           reading=0;         }          //***注意Init中各通道寄存器0x10-0x17的时钟分频***// //*******以下四步计算根据datasheet P19公式*******//       for(i=0;i<=3;i++)     {              CAP_Data = (CAP_Data * 40000000.0F)/268435456.0F;//得到F(sensorx)                   CAP_Data = CAP_Data * 2.0F *3.1515926F;           CAP_Data = 1.0F/((CAP_Data * CAP_Data) * 0.000018F);           CAP_Data = CAP_Data - 0.000000000033F;                   CAP_Data = CAP_Data * 1000000000000.0F;//F转换pF;                   //allData=CAP_Data;                    }         } /***********************************/ /******FDC2214检测电容值程序********/ /************************************/ double GetCapacitance(unsigned long value) {     double pi = 3.14159265359;     double L = 18; //uH     double Cboard = 33; //pf     double Cparacitic = 3; //pf     unsigned long long fsensor;     double temp;               fsensor = 1 * 40000000 * value;     fsensor = fsensor / pow(2,28);         temp = 2 * pi * fsensor;       temp = temp * temp;                     temp = temp / 1000000; //uH     temp *= L;     return temp; }

  • 发表了主题帖: MSP430单片机按键测试KEY函数

    本帖最后由 Jacktang 于 2019-2-15 20:24 编辑 MSP430单片机KEY函数 单片机源程序如下: /******************************************************************** //DM430-L型最小系统板4位独立按键测试程序,采用查询模式 //按不同的按键,显示不同的LED灯,具体请看程序 //调试环境:EW430 V5.30 //时间:2014.03.01 ********************************************************************/ #include <msp430x14x.h> #include "Config.h" uchar key; //************************************************************************* //        初始化IO口子程序 //************************************************************************* void Port_init() {   P1SEL = 0x00;                   //P1普通IO功能   P1DIR = 0xF0;                   //P10~P13输入模式,外部电路已接上拉电阻   P6SEL = 0x00;                   //P6口普通IO功能   P6DIR = 0xFF;                   //P6口输出模式 } //********************************************************************** //        键盘扫描子程序,采用逐键扫描的方式 //********************************************************************** uchar Key_Scan(void) {   uchar key_check;   uchar key_checkin;   key_checkin=KeyPort;                  //读取IO口状态,判断是否有键按下   key_checkin&= 0x0F;                          //读取IO口状态,判断是否有键按下   if(key_checkin!=0x0F)                    //IO口值发生变化则表示有键按下     {       delay_ms(20);                          //键盘消抖,延时20MS       key_checkin=KeyPort;       if(key_checkin!=0x1F)         {             key_check=KeyPort;           switch (key_check & 0x0F)             {               case 0x0E:key=1;break;               case 0x0D:key=2;break;               case 0x0B:key=3;break;               case 0x07:key=4;break;             }                   }           }   else    {      key=0xFF;            }   return key; } //************************************************************************* //                主程序 //************************************************************************* void main(void) {        WDT_Init();                            //看门狗设置   Clock_Init();                          //系统时钟设置   Port_init();                           //系统初始化,设置IO口属性   delay_ms(100);                         //延时100ms   while(1)     {       Key_Scan();                       //键盘扫描,看是否有按键按下       if(key!=0xff)                     //如果有按键按下,则显示该按键键值1~4         {           {             switch(key)               {                 case 1: LED8 = 0xFC;break;        //给不同的键赋键值,键值1,亮2个LED灯                 case 2: LED8 = 0xF3;break;        //给不同的键赋键值,键值2,亮2个LED灯                 case 3: LED8 = 0xCF;break;         //给不同的键赋键值,键值3,亮2个LED灯                 case 4: LED8 = 0x3F;break;         //给不同的键赋键值,键值4,亮2个LED灯               }           }                 }      else       {         //LED=key;                      //没有按键的时候显示上次的键值       }     } }

  • 发表了主题帖: MSP430F149读写RC522 RFID模块的源代码

    单片机源程序如下:                                                                         // //===========================================================================// #include "msp430x14x.h" #include "PIN_DEF.H" #include "RC522.H" #include "UART0_Func.c" #include "ctype.h" #include "BoardConfig.h" unsigned char UID[5],Temp[4]                                       ; unsigned char RF_Buffer[18]                                        ; unsigned char Password_Buffer[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}   ; // Mifare One 缺省密码 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 Auto_Reader(void) {   while(1)   {     if(PcdRequest(0x52,Temp)==MI_OK)     {       if(Temp[0]==0x04&&Temp[1]==0x00)             PutString("MFOne-S50");         else if(Temp[0]==0x02&&Temp[1]==0x00)           PutString("MFOne-S70");         else if(Temp[0]==0x44&&Temp[1]==0x00)           PutString("MF-UltraLight");         else if(Temp[0]==0x08&&Temp[1]==0x00)           PutString("MF-Pro");         else if(Temp[0]==0x44&&Temp[1]==0x03)           PutString("MF Desire");         else           PutString("Unknown");       if(PcdAnticoll(UID)==MI_OK)       {         PutString0("Card Id is:");         tochar(UID[0]);         tochar(UID[1]);         tochar(UID[2]);         tochar(UID[3]);         while (!(IFG1 & UTXIFG0));         TXBUF0 = '\n';                              //发送换行指令         RED_LED_ON                                            ;         Delay(200)                                           ;         RED_LED_OFF                                           ;         Delay(200)                                           ;       }     }   else GRE_LED_OFF                                            ;   } } void Find_Card(void) {     if(PcdRequest(0x52,Temp)==MI_OK)     {       if(Temp[0]==0x04&&Temp[1]==0x00)             PutString("MFOne-S50");         else if(Temp[0]==0x02&&Temp[1]==0x00)           PutString("MFOne-S70");         else if(Temp[0]==0x44&&Temp[1]==0x00)           PutString("MF-UltraLight");         else if(Temp[0]==0x08&&Temp[1]==0x00)           PutString("MF-Pro");         else if(Temp[0]==0x44&&Temp[1]==0x03)           PutString("MF Desire");         else           PutString("Unknown");         PutString("SUCCESS!");     }     else PutString("Faile!");                                              } 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                     ; } /******************************************* 函数名称:HandleConfigMenu 功    能:处理PC的配置函数 参    数:inputvalue--接收到的来自PC机的字符 返回值  :无 ********************************************/ void HandleConfigMenu(uchar inputvalue) {     switch(toupper(inputvalue))     {     case 'A':               Auto_Reader();               break;     case 'F':               Find_Card();               break;     default:               DisplayConfigMenu();       } } void main( void ) {   WDTCTL     = WDTPW + WDTHOLD                                     ; // 关看门狗   BoardConfig(0xf0);   Init_Port();   InitUART();   _EINT()                                            ;   PcdReset();//复位RC522   PcdAntennaOn();//开启天线发射   DisplayConfigMenu();   while(1)   {         Send1Char('>');         Send1Char('\n');         i=Get1Char();         HandleConfigMenu(i);   } }

  • 发表了主题帖: 蓝牙模块的各个接口

    想要玩转蓝牙的硬件工程师,对于蓝牙模块上的各种接口如果不了解的话,那么你就不是一个合格的硬件工程师。那么蓝牙模块上的通讯接口你有了解透彻吗?很多人听到UART接口、IIC接口、SPI接口什么的就会晕,那今天就来简单的概述一些常见的接口与区别。 其实,数据传输的接线方式,大体上就是两种:一种是并行接口,另一种是串行接口。 并行接口是什么?就是我们通常说的并口,是用并行方式来传输数据的接口。所谓“并行”是指数据通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。 串行接口是什么?就是我们常说的串口,是指数据在有限的几个IO上按照顺序,一位一位的进行传输。这类有很多,一般包括:UART、IIC、SPI、CAN、USB等等,只要是串行传输的接口,都是串口的一种。这里值得一说的是,由于早期人们都习惯把UART口称为串口,所以大家所说串口的时候一般特指UART接口。 并行接口和串行接口各有哪些优缺点? 1、串行接口 优点:使用的数据线少,在远距离通信中可以节约通信成本。 缺点:因为每次只能传输一位数据,所以传输速度比较低。 2、并行接口 优点:因为可以多位数据一起传输,所以传输速度很快。 缺点:内存有多少位,就要用多少数据线,所以需要大量的数据线,成本很高。 USART、SPI、IIC的区别 UART接口: UART(Universal AsynchronousReceiver/Transmitter,即通用异步收发器)串行接口是单片机最常用的一种通信技术,通常用于单片机和电脑之间以及单片机和单片机之间的通信。 SPI接口: SPI(Serial Peripheral Interface)就是串行外围设备接口。SPI是一种同步串行数据传输标准,也是一种高速的、全双工、同步的通信总线,在很多器件中被广泛应用。 IIC接口: IIC(Inter-Integrated Circuit,集成电路总线)又称 I2C,一种两线式串行的总线结构,用于连接微控制器及其外围设备。 IIC总线最主要的优点是简单性和有效性。 区别1、UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少。数据是异步传输的,对双方的时序要求比较严格,通信速度也不是很快。在多机通信上面用的最多。 区别2、SPI接口和上面UART相比,多了一条同步时钟线,上面UART的缺点也就是它的优点了,对通信双方的时序要求不严格不同设备之间可以很容易结合,而且通信速度非常快。一般用在产品内部元件之间的高速数据通信上面,如大容量存储器等。 区别3、IIC接口也是两线接口,它是两根线之间通过复杂的逻辑关系传输数据的,通信速度不高,程序写起来也比较复杂。一般单片机系统里主要用来和24C02等小容易存储器连接。 注:SPI和UART可以实现全双工,但I2C不行;I2C的速度比SPI慢一点,协议比SPI复杂一点,但是连线也比标准的SPI要少。

  • 发表了主题帖: AT2401C Zigbee芯片引脚图与技术介绍

    AT2401C 是一款面向 Zigbee,无线传感网络以及其他 2.4GHz 频段无线系统的全集成射频功能的射频前端单芯片。AT2401C 是采用CMOS 工艺实现的单芯片器件,其内部集成了功率放大器(PA),低噪声放大器(LNA),芯片收发开关控制电路,输入输出匹配电路以及谐波滤波电路!该芯片的常规应用主要包括工业控制自动化,智能家居和符合RF4CE 协议的射频系统中。由于该芯片有非常优越的性能,高灵敏度和效率,低噪声,产品尺寸小以及低成本,使得 AT2401C 对于频率带宽内的应用而言成为完美的解决方案。AT2401C 的功能控制逻辑电路非常简单,而且使用了少量的外围器件,可以非常方便系统的整体集成设计。 引脚图: 主要应用 Ø ZigBee 及其相关应用 Ø ZigBee 智能电源方案 Ø 无线音频系统 Ø 智能家居和工业自动化 Ø 无线传感网络 Ø 2.4 GHz 射频系统 特性 Ø 2.4 GHz ZigBee 高效单芯片射频前端集成芯片 Ø 集成 TX/RX 收发器端口和天线端口 Ø 带谐波抑制的 2.4GHz 功率放大器 Ø 低噪声放大器 Ø 发射/接收开关切换电路 Ø 满足发射符合 OQPSK 调制标准的高线性信号的应用要求 Ø 低电压 CMOS 逻辑控制 Ø 所有端口的 ESD 保护电路 Ø RF 端口均有 DC 隔直电路 Ø 电源信号 VDD 与射频信号有良好地内部隔离电路 Ø 接收通道有低的噪声系数 Ø 非常低的直流功耗 Ø 集成全部的匹配以及隔离电路 Ø 仅需少量的外部器件 Ø 输入输出匹配到 50-Ohm Ø 采用性能稳定的 CMOS 工艺 Ø 采用 QFN 3*3*0.75 mm 的下极板接地的小封装 跟进口RFX2401C PIN对PIN完全兼容,价格成本更低,功率具有更优化!

  • 2019-02-14
  • 发表了主题帖: 胞弟NFC和胞哥蓝牙有何不同

    印象中,NFC和蓝牙都同属于短距离通信技术,那它们的区别有哪些? NFC英文全称Near Field Communication,俗称近场通信技术,顾名思义,它是一个近距离通信的产物。它是由飞利浦公司发起,由诺基亚、索尼等多家公司厂商联合主推的一项无线技术。 而蓝牙(Bluetooth)是近距离无线数据通讯技术标准。它能够在10 米的半径范围内实现单点对多点的无线数据和声音传输,其数据传输带宽可达1Mbps。通讯介质为频率在2.402GHz到2.480GHz之间的电磁波。 频率与传输距离的不同: NFC工作于13.56MHZ频率范围,信号传输距离10cm左右。 蓝牙的工作频段为2.4 GHz无线电频段,传输距离一般通常在10米甚至100米(具体情况以模块和实际地形为准)。 功能的不同: NFC有三种工作模式:数据传输,读写,卡模拟。 而蓝牙只是数据传输用的, NFC 的使用距离非常近,而且加密性非常的强,几乎不存在数据拦截的情况,所以我们一般都是用来小额支付等操作的。另外我们还可以用NFC的卡模拟功能来当公交卡使用,还是很方便的。对于这些蓝牙就无能为力了,因为其硬件底层本来就不支持这些。 方便程度的不同: 蓝牙功能是需要预先配对,然后相互信任之后才可以传送数据;而NFC则不必提前配对,直接可以近距离传输,非常方便。 结束语: NFC的出现其实很大程度上是在扩展数码设备的使用环境和领域,并不是要替代蓝牙功能,所以我们完全没有必要担心蓝牙会被NFC取代的问题,两人各有分工,并不是敌对关系。(文字整理自网络)

  • 发表了主题帖: 低功耗蓝牙的应用领域

    十多年来,蓝牙在短距离无线通信领域占据举足轻重的地位。不论是手机、平板、PC还是耳机、游戏手柄、音响、电视、手环、电子秤等,均有蓝牙的应用身影。 传统蓝牙功耗高,在体积小的智能手环、耳机、手机、游戏手柄等产品上力不从心,难以满足人们对待机功能的需求。在这一现实需求下,功耗低,一个纽扣电池可以使用几十天甚至一年的低功耗(BLE)蓝牙如雨后春笋一般飞速发展。 低功耗蓝牙BLE(Bluetooth Low Energy)技术,是蓝牙V4.0核心规范的一部分,主要针对蓝牙功耗方面进行了深层优化,可以满足设备进行低功耗、常期的无线连接要求。最初由诺基亚开发,2010年由蓝牙技术联盟正式对外发布 。 低功耗蓝牙具有智能连接、峰值电流/平均电流和空闲模式下电流消耗少、成本低等优势。当前主力智能手机都嵌入了低功耗蓝牙,使用方便、广泛、普及。而除了手机等移动设备外,低功耗蓝牙还普遍应用在其他的商业、工业领域。 彩灯控制 把低功耗蓝牙模块内置于LED内,即可通过APP控制灯泡的色彩、亮暗。 在智能家居、连锁酒店、办公室、饭店等需要灯光控制调节的地方均可以内置低功耗蓝牙模块,改进设备的智能化和时尚化。 计算机外设、I/O设备以及娱乐交互设备 采用低功耗蓝牙技术,相较传统蓝牙键盘鼠标,低功耗蓝牙鼠标键盘功耗更低,配对连接更快速、使用更加方便。如在现有的鼠标、键盘等产品内嵌入BLE蓝牙模块,可以快速实现产品的升级和智能化!在无线键盘、鼠标、多点触控触摸板、遥控、3D 眼镜、游戏控制器、遥控玩具等领域均极大的潜力。 小家电 将BLE蓝牙模块内置在传统小家电里面,例如豆浆机、电饭煲、电风扇等,增加低功耗蓝牙控制,将其升级为更加智能的家电设备,通过智能手机对小家电进行开关、预约等各种控制,给生活带来不一样的体验。 智能医疗健康 低功耗蓝牙为医疗保健应用提供了一个理想的解决方案。可以大规模的使用高集成、小体积、集成微处理器SOC的芯片小型化封装,然后可通过智能手机与现有内置低功耗蓝牙手机的无缝连接。可用于健康/健身传感器和监控设备、健康体重秤, 血糖计, 血压计, 脉搏血氧仪, 心率带, 活动传感器等。 Beacon室内定位 Beacon 是建立在低功耗蓝牙协议基础上的一种广播协议。一款Beacon设备,可以用在超市商品促销,任何走进它的顾客都会受到beacon推送的促销信息或者优惠券等。超市Beacon商品推广、消息推送、室内定位导航(包括商场、图书馆、停车场、酒店、饭店等等)、景点语音介绍、身份识别等均可使用低功耗蓝牙技术。 蓝牙防丢器 将蓝牙防丢器与智能手机进行连接,设定防丢距离,将防丢器放置在需要看护的物品或者是儿童、宠物身上,当被看护的对象离开手机超过一定的距离,手机就会发起报警,提醒丢失,以起到更好的看管作用。

  • 发表了主题帖: 让新手快速了解zigbee----zigbee概论

    让新手快速了解zigbee

  • 发表了主题帖: 不用频率计矫正ICOM IC-725频偏

    收了一台全新的ICOM的IC-725,作为收藏和研究用,使用中觉得该机操作简单便捷,接收不错,但频率有70HZ的频偏,正常显示的频率下听HAM的语音有变调,用725的RIT旋钮可以矫正接收频率,但却不能矫正发射频率,以至于和熟悉朋友通联时朋友说我的声音变调,听不出是我自己。 为了证实这个情况,我自己做了一个测试:在家里另一个房间里放一台857D,频率设置在14.280MHZ,857的扬声器输出接FM无线耳机发射器,这样我就可以在电台室用无线耳机实时监听自己的声音了。在电台室用725发射,从无线耳机中确实听到了自己的声音有变调,725频率必须调整到14.280.07音调才正常,看来必须设法调一下725的频率了,否则觉得很不方便,不爽。 没有频率计,只好动脑筋了,我是搞音乐的,就利用了一下自己的专业特长,我用857的USB模式收听5.000HMZ授时台信号,发现有两个音频信号,USB模式下,准确音高为C和降E(简谱里的1和降3),换到725 的USB上听,明显音高低了一个半音,以这个为准,心里就知道怎样调整了。 打开725的后盖,可见一大一小两个屏蔽盒,撬开小屏蔽盒的盖子,可见中间有一个可调电容,就是调整它了。把725的频率调到5.000MHZ  USB模式下,等音高信号出现时,对照钢琴的音高,调节该电容,直到该信号的音高和钢琴上的一致为止,当然这需要音高的听辨能力了,音乐上叫“练耳”,没想到会用在无线电上,呵呵! 调整完毕,725调到14.280MHZ,用老方法,725发射,无线耳机收听,发现音调完全准确了,换了几个频率和模式,也没有问题,盖上机盖,在14.270收听了一下,语音正常了,频率调高一点调低一点都会变调,就是14.270上是正常的,试着通联了一下,对方也反映正常,看来大功告成了! 这种调法,可能不能做到绝对的准确,但用耳朵是无法分辨出差别了,机子可以认为完全准确了! 考虑到725机子新旧不同,情况不一,可能不能完全套用到别的同型号机子上,所以本调整方法仅供大家参考了。

  • 发表了主题帖: 初学锁相环

    锁相环的作用:能对输入信号(相位)进行跟踪(还有别的作用,如鉴频、鉴相)。 锁相环的组成 组成:锁相环是一个闭环控制系统,它由下列部分组成:PD(鉴相器)、LF(滤波器)、VCO(压控振荡器)、反馈回路。 基本概念 锁定状态、跟踪状态、捕捉带、同步带。 各部分的功能。 PD:是一个  电压关于相位的函数—u1(t)=f(θe) LF: 对PD所输出的电压进行滤波。同样也输出一个电压量u2(t) VCO:这个玩意是一个把电压的变化变成频率的变化的东东。所以它输出的相位θ2(频率的积分) 反馈回路:作用就是把VCO输出的相位返回给PD,让它与输入的相位θ1求差,得到θe。 如此不停的循环,最终,要让输出的相位θ2与输入的相位θ1之间为常数,达到锁相的功能(锁相环处于锁定状态或跟踪状态)。 具体分析。 PD的数学模型 PD有很多种,现在就最常用的一种--乘法器进行说明 输入与输出共同作用于乘法器后,得到的信号是关于相位差的正弦函数。因此PD的数学模型是一个正弦运算函数sin[θe]。 LF的数学模型 它就是一个低通的滤波器,用来滤掉频率高的信号。常用的有三种:RC积分、无源的比例(积分)、有源的比例(积分)。(数学模型不好打,所以省略) VCO的数学模型 因为它的电压的变化引起频率的变化,所以数学模型是ω(t)= ωo+ku(t)或者用相位表示(θ(t)=ωo?t+ku(t)÷p,p表示微分因子),ωo是VCO固有的频率,ku(t)表示电压的变化量所引起的频率变化量。 反馈回路的数学模型 为简单起见(目前我也只见过这种),反馈回路的数学模型就是1,即输出多少,反馈给输入也是多少。 有了环路各部分基本的数学模型,所以就能得到整个环路的数学模型H(θ)了(传递函数).那么对各种信号的输入,我所要的输出也就能分析出来了。 时域跟踪与频域跟踪 假设输入的相位是一个阶跃量。那么它通过环路后,将会有一个相位的输出,现在我要实现锁相,,也就是输入与输出的相位只差一个常数。那么就要选择合适的环路模型,使输入经过这个环路后,输出只差一个常数的相位。(这就是环路的时域、频域跟踪性能) 时域跟踪性能指的是:相位的变化以阶跃、斜率、加速度变化时,环路的跟踪性能。 频域跟踪性能指的是:相位的变化是以正弦变化时,环路的跟踪性能。 稳定性与非线性 另外,环路还有稳定性问题,输入的信号经过环路后,导致输出的相位有180°的相移。此时需要选择合适的τ(放电常数)和K(环路增益)以及ε(系统参数)。 对于PD为乘法器的环路,还有它的非线性性能。即当相位差θe超过π/6时,此时的PD不能等效为线性,所以就要分析它的非线性。此时用了一种相轨迹法分析(这种方法真妙)。进而分析出各种环路的捕捉带(能进行跟踪的范围)。为了更好地解决此时的非线性,可以用鉴频鉴相器和电荷泵来作为PD,此时环路的鉴频、鉴相就有了很好的线性(特别的鉴相) 总结:锁相环的中心问题就是对输入信号的跟踪,下面所有的问题都是围绕它进行的。比如:如何跟踪(PD、LF、VCO、反馈)、如何跟踪不同的信号(时域跟踪、频域跟踪)、跟踪存在的问题(稳定性、非线性、噪声)、如何解决来更好的跟踪(电荷泵锁相环、数字锁相环)。这些问题大部分都是用的数学工具来分析的,比如傅氏变换、拉氏变换、相轨迹法等等。 以上是我学完这门课程后的初步总结。

  • 2019-02-13
  • 发表了主题帖: 带插补计算的四象限步进电机控制仿真与单片机源程序

    51单片机使用ULN2003A芯片驱动步进电机程序加Proteus仿真 单片机源程序如下: #include<reg51.h> #define uint unsigned int #define uchar unsigned char sbit KEY1=P1^0; sbit KEY2=P1^1; sbit KEY3=P1^2; sbit KEY4=P1^3; sbit KEY5=P1^4; sbit KEY6=P1^5; sbit KEY7=P1^6; uchar code motor_1[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09,                                           0x10,0x30,0x20,0x60,0x40,0xc0,0x80,0x90}; //第一象限 uchar code motor_2[]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09,                                           0x10,0x30,0x20,0x60,0x40,0xc0,0x80,0x90}; //第二象限 uchar code motor_3[]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09,                                           0x80,0xc0,0x40,0x60,0x20,0x30,0x10,0x90};        //第三象限 uchar code motor_4[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09,                                           0x80,0xc0,0x40,0x60,0x20,0x30,0x10,0x90}; uchar code shuma[]={0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //第四象限 uchar bushu[50];  //路径存储 int F,Xe=0,Ye=0,J,Xm=0,Ym=0,dat=0,xiangxian=0; uint key_flag=0,key_change=0,chabu_flag=0,motor_flag=1,start_flag=0; void keyscan(void);                                               //获取按键 void chabu(void);                                                //插补计算 void start(void);                                                //步进电机执行与数码管显示 void main(void) {         EA = 1;                                           /*************************************/         ET0 = 1;                                                                    TMOD = 0x01;                                                 //定时器初始化//         TH0= (65536-1000) / 256;                                 TL0= (65536-1000)%256;          /*************************************/         TR0 = 1;         while(1)         {                   keyscan();                                                                  //按键计数获取                 chabu();                                                                  //插补计算,生成步数轨迹                 start();                                                                  //电机按照轨迹运行         } } void keyscan(void) {         static uint key_up=1;         if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0||KEY5==0||KEY6==0||KEY7==0))         {                 key_up=0;                                                      // 不支持连按。                       if(key_change==1)                                                  //消抖,等待10ms                 {                         if(KEY1==0)         Xe++;                         if(KEY2==0)  Ye++;                         if(KEY3==0) {key_flag=1;xiangxian=1;}                         if(KEY4==0) {key_flag=1;xiangxian=2;}                         if(KEY5==0) {key_flag=1;xiangxian=3;}                         if(KEY6==0) {key_flag=1;xiangxian=4;}                         if(KEY7==0) {P0=0X99;}                 }         }         else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1&&KEY5==1&&KEY6==1)key_up=1;//按键松开         } void chabu(void) {         int i,a=0,b=0;                  if(key_flag==1)         {                 J=Xe+Ye;                 for(i=0;i<J;i++)                 {                         F=((Ym*Xe)-(Xm*Ye));                           //插补计算公式                         if(F==0||F>0)                                        //如果F大于等于零往X方向走                         {                                 a++;                                 if(a==8)a=0;                                 bushu=(a-1);                                 Xm++;                                 }                         else                                                         //否则往Y方向走                         {                                 b++;                                 if(b==8)b=0;                                 bushu=(b+7);                                 Ym++;                         }                         if(i==(J-1))                                         //判断是否到达终点                         {                                 chabu_flag=1;                                 key_flag=0;                                 start_flag=1;                                 }                         }                         }         } void start(void) {                  if(chabu_flag==1&&motor_flag==1&&start_flag==1&&xiangxian==1)//判断是否为第一象限         {                            motor_flag=0;                 P0=motor_1[bushu[dat]];                 if(bushu[dat]<8)                 {                         P2=shuma[bushu[dat]];                 }                 else                 {                         P3=shuma[(bushu[dat]-8)];                 }                 if(dat==(J-1))                 {                         Xe=0;Ye=0;Xm=0;Ym=0;dat=0;              //初始化变量                         key_flag=0;key_change=0;chabu_flag=0;                         motor_flag=1;start_flag=0;              //初始化标志量                 }                 }         if(chabu_flag==1&&motor_flag==1&&start_flag==1&&xiangxian==2)//判断是否为第二象限         {                            motor_flag=0;                 P0=motor_2[bushu[dat]];                 if(bushu[dat]<8)                 {                         P2=shuma[bushu[dat]];                 }                 else                 {                         P3=shuma[(bushu[dat]-8)];                 }                 if(dat==(J-1))                 {                         Xe=0;Ye=0;Xm=0;Ym=0;dat=0;              //初始化变量                         key_flag=0;key_change=0;chabu_flag=0;                         motor_flag=1;start_flag=0;              //初始化标志量                 }                 }         if(chabu_flag==1&&motor_flag==1&&start_flag==1&&xiangxian==3)//判断是否为第三象限         {                            motor_flag=0;                 P0=motor_3[bushu[dat]];                 if(bushu[dat]<8)                 {                         P2=shuma[bushu[dat]];                 }                 else                 {                         P3=shuma[(bushu[dat]-8)];                 }                 if(dat==(J-1))                 {                         Xe=0;Ye=0;Xm=0;Ym=0;dat=0;              //初始化变量                         key_flag=0;key_change=0;chabu_flag=0;                         motor_flag=1;start_flag=0;              //初始化标志量                 }                 }    if(chabu_flag==1&&motor_flag==1&&start_flag==1&&xiangxian==4) //判断是否为第四象限         {                            motor_flag=0;                 P0=motor_4[bushu[dat]];                 if(bushu[dat]<8)                 {                         P2=shuma[bushu[dat]];                 }                 else                 {                         P3=shuma[(bushu[dat]-8)];                 }                 if(dat==(J-1))                 {                         Xe=0;Ye=0;Xm=0;Ym=0;dat=0;              //初始化变量                         key_flag=0;key_change=0;chabu_flag=0;                         motor_flag=1;start_flag=0;              //初始化标志量                 }                 } } void Timer0( ) interrupt 1 {         static uchar key_jishu=0,motor_jishu=0,motor_jishu_a=0;         TR0 = 0;         TH0= (65536-1000) / 256;                                                 //定时1ms         TL0= (65536-1000)%256;         key_jishu++;                 if(key_jishu==10&&key_change==0)                                 //按键延时         {                 key_change=1;                                                                 //按键标志量置1                 key_jishu=0;                                                                 //计数清零         }                                                                        if(chabu_flag==1)                                                                   //计数10ms的次数,因为500太大         {                 motor_jishu++;                 if(motor_jishu==10)                 {                         motor_jishu_a++;                         motor_jishu=0;                 }         }         if(motor_flag==0&&motor_jishu_a==50)                                 //50ms计时         {                 motor_flag=1;                                                                        //电机标志量置1                 dat++;                                                                                         //数组位置,电机步数                 motor_jishu_a=0;                                                                 //计数值清零         }         TR0 = 1;         }

  • 发表了主题帖: DAC0832生成锯齿波的仿真与单片机源码

    单片机源程序如下: /***************   writer:shopping.w   ******************/ #include <reg52.h> #include <absacc.h> #define uint unsigned int #define uchar unsigned char #define DAC0832 XBYTE[0xfffe] void DelayMS(uint ms) {          uchar i;         while(ms--)         {                  for(i=0;i<120;i++);         } } void main() {          uchar i;         while(1)         {                  for(i=0;i<256;i++)                 DAC0832 = i;                 DelayMS(1);         } }

  • 发表了主题帖: 简易单片机计算器的实现

    单片机源程序如下: #include <REG52.H>          //51单片机标准寄存器声明头文件 #include "bsp_GOG1.h"   //这个头文件用于映射GOG1学习板载硬件接口 /*计算器的运算状态定义:*/ #define NoKey       0xaa  //没有按键按下的状态 #define ErrKey      0xff  //错误的按键状态/干扰 #define DpyErr            0x0e  //错误显示状态(码表数组第14个元素:'E') #define DpyCle      0x10  //清屏(码表数组第16个元素:0xff 关闭数码管) #define InCount         0xf0  //有运算符输入状态 #define InErrEqu          0x0f  //有等号输入状态 #define NoCountFlag 0xa5  //没有运算符的状态 /*矩阵按键 功能定义: */ #define ADD        15          //'#':加法  S15 #define SUB        12          //'C':减法  S12 #define MUL        14          //'*':乘法  S13 #define DIV        11          //'B':除法  S8 #define EQU        13          //'D':等于  S16 #define CLE 10    //'A':清除  S4 /*相关子函数的声明:*/ void delayms(unsigned int ms);                          //延时函数 void SegDisplay(unsigned char casebit);         //数码管显示函数 unsigned char ReadKeyPad(void);          //读取矩阵键盘函数 void Timer0Init(void);                                         //定时器0初始化函数 unsigned char CheckInput(void);                         //计算器检查输入状态函数 void DatUnpack(unsigned int dat);                 //计算器数据拆分函数 bit CheckNum(unsigned int dat);                         //计算器数据有效性检查函数 void WarmDpy(unsigned char err);                 //计算器错误显示函数 void ComputeState(unsigned char dat);         //计算器计算过程函数 //数码管段码表 共阳  17个元素: 0~F & 0xff unsigned char code SegCode[17]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,                                  0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff}; unsigned int Ans;              //运算结果 bit AnsFlag=0;            //运算结果存在标志 bit InFlag1=0;                      //输入有效数字1标志 bit InFlag2=0;                      //输入有效数字2标志 unsigned char CountFlag;  //运算符 unsigned int  temp1=0,temp2=0;//输入的2个运算的数字 unsigned char DisBuff[4]={DpyCle,DpyCle,DpyCle,DpyCle};//数码管显示缓存 /*******************************************************************************   * @brief  mian           (简介)   * @param  无                   (参数)   * @retval 无                   (返回值)   ******************************************************************************/ void main(void)                                    //程序从这里开始 {     unsigned char in;                        //保存单个按键值的变量     CountFlag=NoCountFlag;                //运算符初始状态     Timer0Init();                                //定时器0初始化     while(1)     {         in=CheckInput();         while(in == NoKey) in=CheckInput(); //没有按键按下,在此等待         if(in !=ErrKey)                //按键有效         {           ComputeState(in);           }         else  WarmDpy(DpyErr); //按键无效,报错 'E'     } } /*******************************************************************************   * @brief  ComputeState: 计算过程程序   * @param  unsigned char dat   * @retval 无 *******************************************************************************/   void ComputeState(unsigned char dat) {     unsigned int num;         //保存运算操作数的变量     if(AnsFlag == 1)     //判断上一次运算结果完成标志     {         WarmDpy(DpyCle); //清屏         AnsFlag=0;                 //清除有效运算完成标志     }     if((dat !=InCount)&(dat !=InErrEqu)&(dat <10)) //按下的键为数字     {         if(CountFlag == NoCountFlag) //没有运算符存在,保存第一个数         {             num = temp1;             num *= 10;                                 //输入的数字依次进高位             num += dat;             if( CheckNum(num)==1 )   //判断数据有效性             {                                             //有效在数字范围                 temp1 = num;                  //保存第一个数字                 InFlag1 = 1;         //输入有效数字1标志                 DatUnpack(temp1);    //拆分数据,更新显示缓存             }             else WarmDpy(DpyErr);    //超出范围报错         }         else              //运算符存在 ,保存第二个数         {             num = temp2;             num *= 10;             num += dat;             if(CheckNum(num)==1)             {                 temp2 = num;                 InFlag2 = 1;     //输入有效数字2标志                 WarmDpy(DpyCle); //清除第一个数的显示,消除'余晖'                 DatUnpack(temp2);//更新显示缓存             }             else WarmDpy(DpyErr);         }     }     else    //按下的键为非数字(4则运算符被保存,这里考虑 清除键和 错误等号)     {         if(CLE == dat)                 //按下的为清除键         {             CountFlag = NoCountFlag; //清除运算符             InFlag1 =0;                                 //清除输入有效数字1标志             InFlag2 =0;              //清除输入有效数字2标志             AnsFlag=0;                                 //清除运算结果存在标志             temp1=0,temp2=0;         //清除输入的2个运算数             WarmDpy(DpyCle);                 //清屏             Ans=0;                                         //清除上一次运算结果                  }         if(InErrEqu == dat)                            //运算表达式不完整时,按下等号的情况             WarmDpy(DpyErr);         //报错 'E'     } } /*******************************************************************************   * @brief  ReadKeyPad        用于读取矩阵键盘键值   * @param  无   * @retval 矩阵键盘键值   * @note   键盘键值设置请修改case分支临时变量b的赋值                                                 0xff 作为错误代码,表示读取出错 ******************************************************************************/ unsigned char ReadKeyPad(void) {     unsigned char a,c,b=NoKey; //b 初始值为无按键的状态     KeyPad = 0x0f;    //初始状态,行号(P3^0~P3^3)高电平,列号(P3^4~P3^7)低电平     if(KeyPad != 0x0f)     {         delayms(20);                 //按键消抖动(延时实现)         if(KeyPad != 0x0f)         //按键被按下,初始状态改变         {             a = KeyPad;                 //读取矩阵键盘的行号         }         KeyPad = 0xf0;                 //初始状态反转         c = KeyPad;                         //读取矩阵键盘的列号         a |= c;                                 //按位'或',通过行号,列号唯一确定矩阵按键值         switch (a) {         case 0xee:             b = 1;                          //S1             break;         case 0xed:             b = 4;                          //S5             break;         case 0xeb:             b = 7;                          //S9             break;         case 0xe7:             b = MUL;                  //S13'MUL'             break;         case 0xde:             b = 2;                          //S2             break;         case 0xdd:             b = 5;                          //S6             break;         case 0xdb:             b = 8;                          //S10             break;         case 0xd7:             b = 0;                          //S14             break;         case 0xbe:             b = 3;                         //S3             break;         case 0xbd:             b = 6;                         //S7             break;         case 0xbb:             b = 9;                         //S11             break;         case 0xb7:             b = ADD;                 //S15 'ADD'             break;         case 0x7e:             b = CLE;                 //S4 'CLE'             break;         case 0x7d:             b = DIV;                 //S8 'DIV'             break;         case 0x7b:             b = SUB;                 //S12 'SUB'             break;         case 0x77:             b = EQU;                 //S16 '='             break;         default :                         //没有和 a 的匹配项             b = ErrKey;                 //错误的按键值             break;         }         KeyPad = 0xf0;                        //松手检测         while (KeyPad != 0xf0);        //当没有松手,将在此一直等待     }     return (b);                                //返回读取的按键值 } /******************************************************************************   * @brief  delayms        毫秒级延时函数   * @param  ms        延时的毫秒数 允许值 unsigned int范围   * @retval 无   * @attention   这个函数只是用于12T 8051内核的单片机运行于12Mhz   *****************************************************************************/ void delayms(unsigned int ms)         //延时子程序(晶振12Mhz) {     unsigned char i;     while(ms--)     {         for(i = 0; i < 120; i++);     } } /******************************************************************************   * @brief  SegDisplay 数码管显示&定时器中断程序组成动态显示   * @param  casebit        用于选择数码管的位 允许值 0~4   * @retval 无   * @attention   这个函数需配合定时器中断服务程序   *****************************************************************************/ void SegDisplay(unsigned char casebit) {     Seg7_Bits = 0xff;                             //关闭所有数码管     Seg7_Data =SegCode[DisBuff[casebit]];//先把段码值赋给P1(段选端口)     switch(casebit)     {     case 0:         Seg7_Bit1 = 0;         break;     case 1:         Seg7_Bit2 = 0;         break;     case 2:         Seg7_Bit3 = 0;         break;     case 3:         Seg7_Bit4 = 0;         break;     default :         Seg7_Bits = 0xff;        //关闭所有数码管         Seg7_Data = 0xff;         break;     } } /************************************************************************************   * @brief  DatUnpack:数据拆分,同时把数据的千位,百位,十位,个位赋给显示缓存数组DisBuff[]   * @param  unsigned int dat   * @retval 无   ***********************************************************************************/ void DatUnpack(unsigned int dat) {     if((dat<10))                                     //1位数         DisBuff[0]=dat;     else if((dat<100)&&(dat>=10))         //2位数     {         DisBuff[1]=dat/10;         DisBuff[0]=dat%10;     }     else if((dat<1000)&&(dat>=100))         //3位数     {         DisBuff[2]=dat/100;         DisBuff[1]=dat%100/10;         DisBuff[0]=dat%100%10;     }     else if ((dat<10000)&&(dat>=1000))//4位数     {         DisBuff[3]=dat/1000;         DisBuff[2]=dat%1000/100;         DisBuff[1]=dat%1000%100/10;         DisBuff[0]=dat%1000%100%10;     } } /*******************************************************************************   * @brief  unsigned char CheckInput(): 检查矩阵键盘输入按键的类型(简介)   * @param  无                                                                                                          (参数)   * @retval  数字,功能键(CLE,EQU,+,-,*,/),无按键的状态                          (返回值)   ******************************************************************************/ unsigned char CheckInput(void) {     unsigned char x;     x=ReadKeyPad();         //调用读按键子程序     if(x != ErrKey)         //是否为错误按键值     {         if((x<10)|(x == NoKey)| (x == CLE))//按下的为数字,或没有按键按下,或清除键         {             return (x);         }         else           //按下的为 运算符(四则运算 和 等号)         {             if(x == EQU) // 按下的为 等号"="             {                                                                      switch (CountFlag)                 {                 case ADD:         Ans = temp1+temp2; break;                 case SUB:         Ans = temp1-temp2; break;                 case MUL:         Ans = temp1*temp2; break;                 case DIV:   if (temp2 == 0) //除法分母为0,报错                     {                         WarmDpy(DpyErr);                         break;                     }                     else                     {                         Ans = temp1/temp2;//只计算除法商的整数,暂没有考虑小数                         break;                     }                 }                 if( CheckNum(Ans)&&(InFlag1 ==1)&&(InFlag2 ==1))//检测运算的有效性                                   {                           DatUnpack(Ans);                //运算结果拆分,更新显示缓存                     CountFlag = NoCountFlag;        //清除运算符                     temp1=0,temp2=0;                        //清除运算数字                     AnsFlag = 1;                                //运算结果存在标志                     InFlag1 =0;                                //清除有效数字输入标志                     InFlag2 =0;                     Ans=0;                                        //清除运算结果                     return (NoKey);                        //此次运算完成,返回无按键状态                   }                 else //WarmDpy(DpyErr) ;//运算表达式不完整或结果超出范围,报错                     return (InErrEqu);                 //返回有等号输入的状态                     }             else  //按下的为 4则 运算符(+ ,-,*, /)             {                 CountFlag = x;                 //保存运算符                 return (InCount);                 //返回有运算符输入的状态             }         }     }     else  return (ErrKey);                //返回错误按键值状态 } /*******************************************************************************   * @brief  CheckNum: 检查计算器运算数的有效性   * @param  dat   * @retval bit 有效: 1,无效: 0   ******************************************************************************/ bit CheckNum(unsigned int dat) {     if (dat < 10000)         return 1;          //数据有效     else         return 0; } /*******************************************************************************   * @brief  WarmDpy:数码管错误显示   * @param  err                实则:'E'的码段值元素的下标   * @retval 无   ******************************************************************************/ ……………………

  • 发表了主题帖: 51单片机ds18b20仿真+详细注释的代码

    单片机源程序如下(带有详细的注释): #include<reg51.h> #include<lcd1602.h> #include<18b20.h> #define uchar unsigned char #define uint unsigned int bit flag1s = 0;          //1s定时标志 unsigned char T0RH = 0;  //T0重载值的高字节 unsigned char T0RL = 0;  //T0重载值的低字节 void ConfigTimer0(unsigned int ms); unsigned char IntToString(unsigned char *str, int dat); extern bit Start18B20(); extern bit Get18B20Temp(int *temp); extern void InitLcd1602(); extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str); void main() {     bit res;     int temp;        //读取到的当前温度值     int intT, decT;  //温度值的整数和小数部分     unsigned char len;     unsigned char str[12];     EA = 1;            //开总中断     ConfigTimer0(10);  //T0定时10ms     Start18B20();      //启动DS18B20     InitLcd1602();     //初始化液晶     while (1)     {         if (flag1s)  //每秒更新一次温度         {             flag1s = 0;             res = Get18B20Temp(&temp);  //读取当前温度             if (res)                    //读取成功时,刷新当前温度显示             {                 intT = temp >> 4;             //分离出温度值整数部分                 decT = temp & 0xF;            //分离出温度值小数部分                 len = IntToString(str, intT); //整数部分转换为字符串                 str[len++] = '.';             //添加小数点                 decT = (decT*10) / 16;        //二进制的小数部分转换为1位十进制位                 str[len++] = decT + '0';      //十进制小数位再转换为ASCII字符                 while (len < 6)               //用空格补齐到6个字符长度                 {                     str[len++] = ' ';                 }                 str[len] = '\0';              //添加字符串结束符                 LcdShowStr(0, 0, str);        //显示到液晶屏上             }             else                        //读取失败时,提示错误信息             {                 LcdShowStr(0, 0, "error!");             }             Start18B20();               //重新启动下一次转换         }     } } /* 整型数转换为字符串,str-字符串指针,dat-待转换数,返回值-字符串长度 */ unsigned char IntToString(unsigned char *str, int dat) {     signed char i = 0;     unsigned char len = 0;     unsigned char buf[6];     if (dat < 0)  //如果为负数,首先取绝对值,并在指针上添加负号     {         dat = -dat;         *str++ = '-';         len++;     }     do {          //先转换为低位在前的十进制数组         buf[i++] = dat % 10;         dat /= 10;     } while (dat > 0);     len += i;     //i最后的值就是有效字符的个数     while (i-- > 0)   //将数组值转换为ASCII码反向拷贝到接收指针上     {         *str++ = buf[i] + '0';     }     *str = '\0';  //添加字符串结束符     return len;   //返回字符串长度 } /* 配置并启动T0,ms-T0定时时间 */ void ConfigTimer0(unsigned int ms) {     unsigned long tmp;  //临时变量     tmp = 11059200 / 12;      //定时器计数频率     tmp = (tmp * ms) / 1000;  //计算所需的计数值     tmp = 65536 - tmp;        //计算定时器重载值     tmp = tmp + 2;            //补偿中断响应延时造成的误差     T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节     T0RL = (unsigned char)tmp;     TMOD &= 0xF0;   //清零T0的控制位     TMOD |= 0x01;   //配置T0为模式1     TH0 = T0RH;     //加载T0重载值     TL0 = T0RL;     ET0 = 1;        //使能T0中断     TR0 = 1;        //启动T0 }

  • 发表了主题帖: MOS管发热异常,排查原因来优化设备运行

    本帖最后由 Jacktang 于 2019-2-13 19:52 编辑 在电路设计的时候常常会发生MOS管发热的情况,而MOS管发热说明了它正在错误运行。为了避免MOS管发热危害到整体设备的运行,所以在再次运行之前需要先排查出MOS管发热的原因。MOS管发热无非是这几种情况,接下来30年经验的MOS管厂家“飞虹”为大家分享一下。 一、电路设计 让MOS管工作在线性的工作状态,而不是在开关状态。如果N-MOS做开关,G级电压要比电源高几V,才能完全导通,P-MOS则相反。没有完全打开而压降过大造成功率消耗,等效直流阻抗比较大,压降增大,所以U*I也增大,损耗就意味着发热。 二、工作频率 这是在调试过程中比较常见的现象,降频主要由两个方面导致。输入电压和负载电压的比例小、系统干扰大。对于前者,注意不要将负载电压设置的太高,虽然负载电压高,效率会高点。对于后者,可以尝试以下几个方面: 1、将最小电流设置的再小点 2、布线干净点,特别是sense这个关键路径 3、将电感选择的小点或者选用闭合磁路的电感 4、加RC低通滤波吧,这个影响有点不好,C的一致性不好,偏差有点大,不过对于照明来说应该够了。无论如何降频没有好处,只有坏处,所以一定要解决。 有些时候,MOS管频率太高,主要是有时过分追求体积,导致频率提高,MOS管上的损耗增大了,所以发热也加大。 三、散热设计 电路板没有做好足够的散热设计,电流太高,MOS管标称的电流值,一般需要良好的散热才能达到。所以ID小于最大电流,也可能发热严重,需要足够的辅助散热片。

  • 2019-02-12
  • 发表了主题帖: DSP28027的spi学习

    刚接触TI公司DSP28027和DSP28335系列芯片,作为一个刚刚进入实验室的小白,想把自己学习的一些心得记录下来,以供以后的自己随时回忆,并学习。 首先,spi(Serial Peripheral Interface)串行外设接口,广泛应用于EEPROM、实时时钟、A/D转换、D/A转换等器件,属于高速、全双工通信总线,占用了四个引脚,分别为MOSI,MISO,CLK,SCS四根线。 利用28027的SPI可以快速方便的进行配置,并发送数据。SPI单词发送数据可以发送16位的数据,利用官方例程中的发送函数: void spi_xmit(Uint16 a) {     SpiaRegs.SPITXBUF=a; } 可以实现简单的16位数据的发送。当然在配置寄存器时要格外注意控制寄存器SPICCR,例如要实现16位数的发送就可以写如下代码: void spi_init() { SpiaRegs.SPICCR.all =0x000F;              // Reset on, rising edge, 16-bit char bits SpiaRegs.SPICTL.all =0x0006;         // Enable master mode, normal phase,                                                                       // enable talk, and SPI int disabled. SpiaRegs.SPIBRR =0x007F;     SpiaRegs.SPICCR.all =0x009F;          // Relinquish SPI from Reset     SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission } 要实现这样简单的功能并不需要配置FIFO寄存器。 然而,往往在控制系统中对于信息的传输不满足于简单的一个数据,往往需要一串数据来实现相应的控制功能。因此我们需要利用到FIFO寄存器来实现多数据的传送。 举个例子,我们需要连续发送4个16位数据,那么除了上述void spi_init()函数,还需要配置FIFO寄存器初始化 void spi_fifo_init() {                                                                SpiaRegs.SPIFFTX.all=0xE040;             // Initialize SPI FIFO 无中断     SpiaRegs.SPIFFRX.all=0x2044;                 SpiaRegs.SPIFFCT.all=0x0;                  //发送无延迟 } 如此,再利用发送函数,就可以实现4个数据的连续发送   for(i=0;i<4;i++) { spi_xmit(spi_TX); } 根据测试结果,可以从示波器上清晰的看到连续的时钟信号,持续64个时钟周期,并且数据也没有错。根据测试结果,F28027按照如上配置最多可以发送5个16位数据,若要发送6个及以上就会出现数据丢失的现象。 上面所述是发送数据为偶数字节的情况,但在实际的使用中,有时需要我们按照字节发送数据,强大的spi模块也可以实现这样的功能。 首先需要改变SPICCR寄存器的字符控制位: void spi_init() { SpiaRegs.SPICCR.all =0x0007;   // Reset on, rising edge, 16-bit char bits字符控制位设置为8字节 SpiaRegs.SPICTL.all =0x0006;         // Enable master mode, normal phase,                                                              SpiaRegs.SPIBRR =0x007F;     SpiaRegs.SPICCR.all =0x0097;          // 字符控制位设置为8字节     SpiaRegs.SPIPRI.bit.FREE = 1;                // Set so breakpoints don't disturb xmission } 在发送时,我们需要注意,SPI的SPITXBUF中的数据应该左对齐,因为发送的时候是从MSB位最先开始发送的,因此在发送时需要把相应的8位数据向左移8位。 例如试图发送数据0xAA,在不右移的情况下 a=0xAA; SpiaRegs.SPITXBUF=a; 只会在8个时钟中期中发送00,因为SPITXBUF寄存器是一个16位的寄存器。因此应该 SpiaRegs.SPITXBUF=(a<<8); 如此,就可以在8个时钟周期发送出一个8位的数据。 如此,在连续发送数据时也可以连续执行发送函数 for(i=0;i<4;i++) { spi_xmit(spi_TX); } 通过测试,F28027通过这种按字节发送的方式,最多可以连续发送5个字节的数据,并保证数据不乱。但这样的发送方式很明显浪费掉了一部分寄存器的位置,有待改进。 以上便是对于SPI的一些心得体会,认知还停留在非常入门的阶段,在今后的学习中希望能解决目前的不足,尽早熟练。

  • 发表了主题帖: TMS320F28027之ADC零点偏移校准

    零点偏移误差被定义为,当转换一个在VREFLO电压时得到的结果。这个基本误差会影响ADC的所有转换,包括满刻度的增益和线性度指标,决定了转换器的直流精度。零点偏移误差可能是正的,或者是负的,正的意味着转换VREFLO时得到一个正的结果。负的意味着转换一个高于VREFLO的电压结果仍会是0。为了更正这种错误,两种误差的补码都会被写入ADCOFFTRIM寄存器。这个寄存器的值在AD转换结果保存到ADC结果寄存器之前会被用到。此操作被完全包含在ADC内核,所以结果的定时将不会受到影响,ADC能够保持全动态范围通过修改微调值。调用Device_cal()把厂家校正的零点偏移写到ADCOFFTRIM寄存器,用户能够修改ADCOFFTRIM的值以减少环境造成偏移误差。这个可以通过设置ADCCTRL1的VREFLOCONV位实现,不需要任何一个ADC通道。 如下步骤重新校准ADC偏移: 1.     Set ADCOFFTRIM to80 (50h) 2.     SetADCCTL1.VREFLOCONV to 1 3.     Perform multiple conversions on B5 (i.e. sampleVREFLO) and take an average to account for board noise 4.     Set ADCOFFTRIM to 80 (50h) minus the averageobtained in step 3 5.     SetADCCTL1.VREFLOCONV to 0. 文件DSP2802x(3x)_Adc.c中的AdcOffsetSelfCal()函数实现了以上操作。

TA暂时无记录哦~

统计信息

已有146人来访过

  • 芯币:4142
  • 好友:--
  • 主题:1364
  • 回复:82
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言