tag 标签: pic24hj

相关博文
  • 热度 17
    2014-1-17 06:44
    3203 次阅读|
    0 个评论
      主函数操作流程: 时钟设置 清中断标志 ECAN1初始化,DMA0,2初始化,使能中断 ECAN2初始化,DMA1初始化 ,使能中断 ECAN2写信息,ECAN1写信息,发送请求 主循环为空,等待中断   ECAN1初始化 void ecan1Init(void){  C1CTRL1bits.REQOP=4;  while(C1CTRL1bits.OPMODE!=4); //进入配置模式  ecan1ClkInit(); //时钟初始化,配置TQ  C1FCTRLbits.FSA=0b10000;//设置FIFO从buffer16开始  C1FCTRLbits.DMABS=0b000;//DMA中开辟32个BUFFER   // FILTER设置   //下面FILTER的设置参数含义为:设置FILTER1,ID为0X1FFFFFFF,拓展模式,指向缓存1,MASK选择0 ecan1WriteRxAcptFilter(1,0x1FFEFFFF,1,1,0); // MASK设置 //下面MASK的设置参数含义为:设置MASK1,所有的位都要比较,模式看后面,模式为拓展模式    ecan1WriteRxAcptMask(1,0x1FFFFFFF,1,1);   //设置完FILTER和MASK,回到常规模式  C1CTRL1bits.REQOP=0;  while(C1CTRL1bits.OPMODE!=0);   //定义BUFFER0和BUFFER1的方向,以及优先级    C1RXFUL1=C1RXFUL2=C1RXOVF1=C1RXOVF2=0x0000;  C1TR01CONbits.TXEN0=1; /* ECAN1, Buffer 0 is a Transmit Buffer */  C1TR01CONbits.TXEN1=0; /* ECAN1, Buffer 1 is a Receive Buffer */  C1TR01CONbits.TX0PRI=0b11; /* Message Buffer 0 Priority Level */  C1TR01CONbits.TX1PRI=0b11; /* Message Buffer 1 Priority Level */ }   ECAN2初始化 void ecan2Init(void){  C2CTRL1bits.REQOP=4; //进入配置模式  while(C2CTRL1bits.OPMODE!=4);  ecan2ClkInit(); //配置时钟TQ  C2FCTRLbits.FSA=0b10000;//FIFO首地址  C2FCTRLbits.DMABS=0b000; //缓存数量  //下面FILTER的设置参数含义为:设置FILTER1,ID为0X1FFFFFFF,拓展模式,指向缓存0,MASK选择0  ecan2WriteRxAcptFilter(1,0x1FFEFFFF,1,0,0); //下面MASK的设置参数含义为:设置MASK1,所有的位都要比较,模式看后面,模式为拓展模式  ecan2WriteRxAcptMask(1,0x1FFFFFFF,1,1);  C2CTRL1bits.REQOP=0;  while(C2CTRL1bits.OPMODE!=0);//进入常规模式  C2RXFUL1=C2RXFUL2=C2RXOVF1=C2RXOVF2=0x0000;  C2TR01CONbits.TXEN0=1; //ECAN2发送  C2TR01CONbits.TX0PRI=0b11; //优先级设置 } DMA初始化 void dma0init(void){   DMACS0=0; //冲突检测清零      DMA0CON=0x2020; //方向为发送,外设直接地址   DMA0PAD=0x0442; /发送地址    DMA0CNT=0x0007; //发送计数   DMA0REQ=0x0046; //写入请求好   DMA0STA= __builtin_dmaoffset(ecan1msgBuf); //地址指向   DMA0CONbits.CHEN=1; //使能通道0 }   void dma1init(void){    DMA1CON=0x2020; //方向为发送,外设直接地址  DMA1PAD=(int)C2TXD; //C2TXD为发送数据寄存器  DMA1CNT=0x0007; //发送计数  DMA1REQ=0x0047; //请求号  DMA1STA= __builtin_dmaoffset(ecan2msgBuf); //DPRAM偏置,地址指向  DMA1CONbits.CHEN=1; //使能CH1     } void dma2init(void){     DMACS0=0; //冲突检测清零      DMA2CON=0x0020; //接收,外设直接地址   DMA2PAD=0x0440; //接收地址    DMA2CNT=0x0007; //接收计数   DMA2REQ=0x0022; //请求号   DMA2STA= __builtin_dmaoffset(ecan1msgBuf); //地址指向   DMA2CONbits.CHEN=1; //使能通道2 }   void dma3init(void){   DMACS0=0;      DMA3CON=0x0020;   DMA3PAD=(int)C2RXD; /* ECAN 2 (C2RXD) */    DMA3CNT=0x0007;   DMA3REQ=0x0037; /* ECAN 2 Receive */   DMA3STA=__builtin_dmaoffset(ecan2msgBuf);   DMA3CONbits.CHEN=1; }   ECAN1写消息 void ecan1WriteMessage(void){  ecan1WriteTxMsgBufId(0,0x1FFEFFFF,1,1);  ecan1WriteTxMsgBufData(0,8,0,0,0,0); } //第一个函数:第一个参数,BUFFER号,第二个参数ID号,第三个,拓展ID标志,第四个,是否是远程帧 //上面的调用,写到缓存0,ID号是0X1FFFFFFF,是拓展帧,是远程帧 void ecan1WriteTxMsgBufId(unsigned int buf, long txIdentifier, unsigned int ide, unsigned int remoteTransmit){ unsigned long word0=0, word1=0, word2=0; unsigned long sid10_0=0, eid5_0=0, eid17_6=0,a;    eid5_0 = (txIdentifier 0x3F); //取得ID号  eid17_6 = (txIdentifier6) 0xFFF;  sid10_0 = (txIdentifier18) 0x7FF;   word1 = eid17_6;    if(remoteTransmit==1) { // 如果是远程帧,将远程帧的标志写入到WORD0和WORD2中   word0 = ((sid10_0 2) | ide | 0x2);   word2 = ((eid5_0 10)| 0x0200);}  else {   word0 = ((sid10_0 2) | ide);   word2 = (eid5_0 10);       }  ecan1msgBuf = word0;//将合成的WORD写入到BUFFER中  ecan1msgBuf = word1;  ecan1msgBuf = word2; } 如果是数据帧,则继续写入数据,如果是远程帧,也可以写入一些无效数据,比如: ecan1WriteTxMsgBufId(0,0x1FFEFFFF,1,1);  ecan1WriteTxMsgBufData(0,8,0,0,0,0);:   void ecan1WriteTxMsgBufData(unsigned int buf, unsigned int dataLength, unsigned int data1, unsigned int data2, unsigned int data3, unsigned int data4){  ecan1msgBuf = ((ecan1msgBuf 0xFFF0) + dataLength) ;  ecan1msgBuf = data1;  ecan1msgBuf = data2;  ecan1msgBuf = data3;  ecan1msgBuf = data4; }   中断函数的处理   上面的程序中,中断有6个,两个为ECAN1和ECAN2的中断,另外四个为DMA0~DMA3的四个中断 ECAN1和ECAN2的中断处理是一样的,具体接收子程序不同。 void __attribute__((interrupt, no_auto_psv))_C1Interrupt(void) {  IFS2bits.C1IF = 0; //清零ECAN1中断标志  if(C1INTFbits.TBIF)     {      C1INTFbits.TBIF = 0; //发送中断?清空就行     }     if(C1INTFbits.RBIF)     {      if(C1RXFUL1bits.RXFUL1==1) //接收?则需要接收程序      {       rx_ecan1message.buffer=1; //设置一个缓存中有数据的标志       C1RXFUL1bits.RXFUL1=0; //清零接收中断标志      }      rxECAN1(rx_ecan1message); //缓存有数据,则开始接收,然后清零标志   C1INTFbits.RBIF = 0;  } }   ECAN1的接收程序: void rxECAN1(mID *message) {  unsigned int ide=0;  unsigned int srr=0;  unsigned long id=0,d;  ide=ecan1msgBuf 0x0001; //将收到的帧的IDE和SRR读出来  srr=ecan1msgBuf 0x0002; //  if(ide==0)  {   message-id=(ecan1msgBuf 0x1FFC) 2; //如果是标准帧,则将ID读出来,并且标记为标准帧   message-frame_type=CAN_FRAME_STD;  }  else //如果是扩展帧,将ID也读出来,放到BUFFER 0/1/2中  {   id=ecan1msgBuf 0x1FFC;   message-id=id 16;   id=ecan1msgBuf 0x0FFF;   message-id=message-id+(id 6);   id=(ecan1msgBuf 0xFC00) 10;   message-id=message-id+id;   message-frame_type=CAN_FRAME_EXT;  } //判断是不是远程帧,如果是远程帧,则将远程帧标志置位  if(srr==1)  {   message-message_type=CAN_MSG_RTR;  } //如果为常规数据帧,则先标志帧类型为数据帧,然后将数据读入DMA的缓存,并且将数据长度也读入到BUFFER2中。  else  {   message-message_type=CAN_MSG_DATA;   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data_length=(unsigned char)(ecan1msgBuf 0x000F);  } }   四个DMA的中断程序都很简单,就是单纯的清标志。   /***************************************************/ 2013年是移动互联网的元年,移动互联网大大提高了我们工作和生活的效率。  罗辑思维用互联网思维网络了大量的会员,最近又在召集用互联网思维来吃霸王餐。  我们不需要那么牛气哄哄,互联网思维既然能够解决这样的大事,那小事当然更没问题。  利用互联网思维做一个晨型人,也应该不是一件难事吧。  操作模式如下:申请一个微信公众号,分享作为晨型人一天的收获。  以及在遇到困难的时候,如果克服自己,解决问题。  如果有兴趣,扫一扫下面的公众号 吧,让我们一起轻松的做一个快乐的晨型人。  /***************************************************/                        
  • 热度 13
    2014-1-17 06:43
    3338 次阅读|
    0 个评论
    学习一下官方提供的ECAN程序的例程: 本程序完成如下的功能: 配置时钟,初始化ECAN和DMA和液晶 发送一个ECAN的帧 在主循环中,判断是否收到帧,收到则进行帧的处理。 程序流程 配置位设置: /***************************************************************************************************** Configuration bits: _FOSCSEL: Start up with the FRC oscillator _FOSC: Use Primary oscillator XT w/ PLL, Two-speed Oscillator Startup enabled _FWDT: Watch dog timer is off _FPOR: Power-on Reset Value disabled, Alternate I2C pins mapped to SDA1/SCL1 _FICD: JTAG is disabled, communicate on PGC3/EMUC3 and PGD3/EMUD3 for explorer 16 development board    *****************************************************************************************************/ _FOSCSEL(FNOSC_FRC) _FOSC(FCKSM_CSECMD POSCMD_XT) _FWDT(FWDTEN_OFF) _FPOR(FPWRT_PWR1) _FICD(JTAGEN_OFF ICS_PGD1)   MPLABX生成的配置字程序,太长了,不是一般的难看。   时钟配置 申明两个全局的结构体,一个是CAN接收消息,一个是CAN发送消息,结构体如下; //消息结构体 typedef struct{  unsigned char buffer_status;//状态  unsigned char message_type;//远程帧还是数据  unsigned char frame_type;//标准模式还是扩展模式  unsigned char buffer;//用来发送和接收的缓存  unsigned long id;//ID号,两种模式  unsigned char data ;//数据域  unsigned char data_length;//数据长度 }mID; 定义消息BUFFER /* Define ECAN Message Buffers */ ECAN1MSGBUF ecan1msgBuf __attribute__((space(dma),aligned(ECAN1_MSG_BUF_LENGTH*16))); char mytext ="TBXXX Demo";      主函数 配置时钟 初始化ECAN,初始化DMAECAN Welcome消息 使能ECAN1中断,使能发送和接收中断 填充结构体,生成一个帧格式 将一个合成的帧发送出去 while循环中做如下的操作 如果BUFFER的状态中,BUF为满,则将消息读到RAM中。 消息显示在液晶上 清消息满的状态 否则做其他的操作   初始化ECAN:     void initECAN (void) {  unsigned long temp;  unsigned int tempint;    C1CTRL1bits.REQOP=4; //进入配置模式,或者用库函数中设置操作模式的函数来编写  while(C1CTRL1bits.OPMODE != 4); //等待确实进入了配置模式     //配置C1CFG1和C1CFG2的值,或者用初始化ECAN的函数来写。  Bit Time = (Sync Segment + Propagation Delay + Phase Segment 1 + Phase Segment 2)=20*TQ  Phase Segment 1 = 8TQ  Phase Segment 2 = 6Tq  Propagation Delay = 5Tq  Sync Segment = 1TQ  CiCFG1 =(FCAN /(2 譔譌BAUD))?1  BIT RATE OF 1Mbps  */  C1CFG1bits.BRP = BRP_VAL;  /* Synchronization Jump Width set to 4 TQ */  C1CFG1bits.SJW = 0x3;  /* Phase Segment 1 time is 8 TQ */  C1CFG2bits.SEG1PH=0x7;  /* Phase Segment 2 time is set to be programmable */  C1CFG2bits.SEG2PHTS = 0x1;  /* Phase Segment 2 time is 6 TQ */  C1CFG2bits.SEG2PH = 0x5;  /* Propagation Segment time is 5 TQ */  C1CFG2bits.PRSEG = 0x4;  /* Bus line is sampled three times at the sample point */  C1CFG2bits.SAM = 0x1;   //设置BUFFER的尺寸。  C1FCTRLbits.DMABS=0b000;    /* Filter configuration */   //使用Filter还是BUFFER,配置完以后,清空,直接指向缓存。  C1CTRL1bits.WIN=0b1;    C1FMSKSEL1bits.F0MSK=0;//选择F1为M0模式  C1RXM0SID=CAN_FILTERMASK2REG_SID(0x7FF);//每位都需要比较!!  C1RXF0SID=CAN_FILTERMASK2REG_SID(0x123);//ID为0X123  C1RXM0SID=CAN_SETMIDE(C1RXM0SID);//MIDE设置为1时候,再看EXIDE是0还是1来决定标准ID模式还是EXID模式。  C1RXF0SID=CAN_FILTERSTD(C1RXF0SID);//将EXIDE设置为0,只接收标准模式  C1BUFPNT1bits.F0BP=0b0001;//缓冲指针指向1,  C1FEN1bits.FLTEN0=1;//使能FILTER0 //上面的整体设置思路是,F0选择M0,然后设置M0是每位都要匹配,然后设置匹配的ID,然手设置成ID模式,选择标准模式,然后设置指向的缓存,再使能配置好了的F0,    C1FMSKSEL1bits.F1MSK=0b01;//选择F1为M2模式  C1RXM1EID=CAN_FILTERMASK2REG_EID0(0xFFFF);//采用扩展模式,这位是全部需要比较  C1RXM1SID=CAN_FILTERMASK2REG_EID1(0x1FFF);//采用扩展模式,标准模式的11要比较,再加上最后两位也需要比较  C1RXF1EID=CAN_FILTERMASK2REG_EID0(0x5678);//29位ID,写入寄存器  C1RXF1SID=CAN_FILTERMASK2REG_EID1(0x1234);//29位ID,写入寄存器  C1RXM1SID=CAN_SETMIDE(C1RXM1SID);//查扩展ID是否匹配  C1RXF1SID=CAN_FILTERXTD(C1RXF1SID);  C1BUFPNT1bits.F1BP=0b0010;//指向缓冲为2  C1FEN1bits.FLTEN1=1;//使能该F1    C1FMSKSEL1bits.F2MSK=0b01;//F2继续使用F1的M1作为规则  C1RXF2EID=CAN_FILTERMASK2REG_EID0(0x5679);//M1已经定义好,不需要再重新定义  C1RXF2SID=CAN_FILTERMASK2REG_EID1(0x1234);//继续写入29位ID到寄存器中  C1RXF2SID=CAN_FILTERXTD(C1RXF2SID);//这里,M里面的那位不再需要定义,直接需要查拓展ID,前面已经定义好  C1BUFPNT1bits.F2BP=0b0011;//指向缓冲  C1FEN1bits.FLTEN2=1;//使能F2            //关掉设置窗口,直接指向缓存  C1CTRL1bits.WIN=0;    //模式设置回正常模式,等待确实回到正常模式  C1CTRL1bits.REQOP=0;  while(C1CTRL1bits.OPMODE != 0);   //接收缓存满,溢出都设置为0  C1RXFUL1=C1RXFUL2=C1RXOVF1=C1RXOVF2=0x0000; //设置四个缓存的方向,是发送还是接收,下面的设置,缓存0为发送,123为接收  C1TR01CONbits.TXEN0=1;  C1TR01CONbits.TXEN1=0;  C1TR23CONbits.TXEN2=0;  C1TR23CONbits.TXEN3=0; //设置缓存0的优先级为最高。  C1TR01CONbits.TX0PRI=0b11;   //再请一次满标志,然后设置满中断标志为0  C1RXFUL1=0;  C1INTFbits.RBIF=0; }     初始化DMA void initDMAECAN(void) { //DMA的通道给DMA作为发送,先情况冲突标志  DMACS0=0;     DMA0CON=0x2020; //第一个位,方向,从DPSRAM中读,写入外设,第二位,外设直接地址模式  DMA0PAD=0x0442; //既然设置成外设直接地址,当然要提供一个外设的地址,ECAN1发送的地址为0X0442   DMA0CNT=7; //要发送的数量  DMA0REQ=0x0046; //这个是请求号,ECAN1的请求号是0X0046  DMA0STA=__builtin_dmaoffset(ecan1msgBuf); //发送的数据指向指针  DMA0CONbits.CHEN=1; //使能通道1   //下面设置的是接收,和发送类似。  DMACS0=0;  DMA2PAD=0x0440;   DMA2CNT=7;  DMA2REQ=0x0022;  DMA2STA=__builtin_dmaoffset(ecan1msgBuf);  DMA2CONbits.CHEN=1; }   液晶显示初始化:略 使能中断 //使能中断,使能ECAN中断,发送中断和接收中断,ECAN一共还有7中中断,包括无效消息中断,总线唤醒,错误中断,FIFO满中断,接收满中断和发送中断,接收中断。  IEC2bits.C1IE=1;  C1INTEbits.TBIE=1;  C1INTEbits.RBIE=1;   合成需要发送的数据帧: //要发送的帧结构体定义  canTxMessage.message_type=CAN_MSG_DATA; //数据帧  //canTxMessage.message_type=CAN_MSG_RTR;  canTxMessage.frame_type=CAN_FRAME_EXT; //扩展帧  //canTxMessage.frame_type=CAN_FRAME_STD;  canTxMessage.buffer=0; //写入的buffer0  canTxMessage.id=0x123; //ID号  canTxMessage.data =0x55; //填入发送的8位数据  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data =0x55;  canTxMessage.data_length=8;//数据长度为8     /***************************************************/ 2013年是移动互联网的元年,移动互联网大大提高了我们工作和生活的效率。  罗辑思维用互联网思维网络了大量的会员,最近又在召集用互联网思维来吃霸王餐。  我们不需要那么牛气哄哄,互联网思维既然能够解决这样的大事,那小事当然更没问题。  利用互联网思维做一个晨型人,也应该不是一件难事吧。  操作模式如下:申请一个微信公众号,分享作为晨型人一天的收获。  以及在遇到困难的时候,如果克服自己,解决问题。  如果有兴趣,扫一扫下面的公众号 吧,让我们一起轻松的做一个快乐的晨型人。  /***************************************************/
  • 热度 19
    2014-1-17 06:41
    2887 次阅读|
    3 个评论
    项目开始的时候,老板要我实现一个流量计,用液晶显示出来,我兴致勃勃的拿到这个项目,完成这样的项目难度应该不大。 之前我只用过51的单片机和AVR的单片机,而学习51单片机的流程是这样的。 上了单片机的课程,自学了汇编语言编程,上大学的时候做了一个MP3的项目,没有调试,淘宝卖家给了源码,我凑合看了一遍,整理出了论文。 单片机的学习从买到的资料开始下手,先拿到资料,写到芯片中,然后看程序,然后改程序,里面的资源基本上就是大学课本上看到过,后面还看了几个视频教程,基本上知道这些外设都是干嘛的 毕业一年后,用到了51单片机,用汇编语言来做的,熟悉了一下汇编,但是没有写过,C语言则用PROTEUS做了一些液晶驱动程序等。 微芯的工作用的少,自己买了一个AVR32的芯片,本来是打算用来做TMC262的项目的,没有做出来,但是为什么要选择AVR32的芯片,基本上都没有想过。 这样的学习过程,其实是很惨的,现在看来,都觉得心惊肉跳,我压根就没有潜心下来看过完整的资料手册,哪怕是中文的也没有仔细看过,需要用到哪块,直接看哪块的程序。 导致我现在都不能说出51单片机的外设资源。至于存储器和RAM之类的,一直也就是只有一个模糊的印象,尤其是程序存储器之类的东西,核结构的问题基本上都没有多大概念。 并且,甚至哪些资源是外设,哪些资源是内核的资源,都么有一个具体的印象,更不要说单片机的执行速度,RAM和ROM的具体大小。带着这样的一个情况,我开始接手这个项目。 有时候我想,当时的视频教程确实让我入门了,郭天祥甚至说C语言汇编语言,模电数电不要懂都么有什么关系,就可以开始编程了,现在看来,当时确实被他的话骗的屁颠屁颠的,但是我确确实实在这个上面栽了一个跟头。   一开始拿到AVR,我继续用的是学习51的那套思路,通过光盘资料和百度,边碰壁边摸索,把测试程序写进去了,然后自己尝试用单片机连接一些外设。SPI,IIC,串口,按键,LED,然后就感觉自己懂了,开始用这个单片机来做驱动器,是的,驱动器转起来了,以为项目不需要量产,就是玩玩的,转起来了就OK了,然后就放在那里,有时候需要给测试平台一些信号,我就用这个板子来发信号,与TMC262的开发,看了通信程序,用示波器来抓,发现没有问题,然后就OK了,如果信号出了问题,就慢慢调整程序,有时候甚至是漫无目的的,抱着试试看的心态。所以研究的结果还是一样的,觉得自己懂了,想做点小项目,但是一直没有开始动手。   接到这个项目,老板要我用PIC的单片机,我之前只是听说过,至于单片机的选型,我是没有一点印象的,觉得资源够就行,里面外设多,自然能够降低开发成本。后来才知道PIC单片机比较稳定,系列比较全。一开始选择用市面上最多的PIC18来做,这样的资料也能找到不少,但是一周下来,把选型的结果提交给老板,老板要求用16位的单片机,并且要CAN总线的功能,这样,经过一周的折腾,芯片一开始定位在PIC24FJ128GA006的一颗芯片上,再一周的样子,改成了现在所用的PIC24HJ128GP506,原因是,之前误认为CAN收发器可以做控制器来使用,可笑。   然后,拿到芯片,开始打了一个最小系统板,有KIT2了,开始调试硬件,写入测试程序。测试程序也很简单,官网上面有例程。按照DATASHEET,开始弄测试程序。还是那样的思路,需要用到哪块就开始补哪块,看哪块的资料,资料里面有的程序也不求甚解,抄过来开始调试,遇到问题,找到相应的寄存器开始弄懂每一位的作用。选用了PIC24HJ这颗芯片后,我决定我不再去网上找一些中文资料,在官网上下载开发工具,编译器,开始下载外设的一些详细资料,去下载和熟悉资料中推荐的一些文档,用笔记记录下来。虽然到现在为止,我还是对这个项目的开发没有一个大概的进度,但是,其他我走了一条之前不一样的路,走的更加稳健,一步一步的,老老实实的来学习,这也算是一个进步吧。   目前完成了芯片手册的熟悉,换成了最新的IDE,也就是MPLAB X,还是有很多的资料需要学习,海量的资料,如果把所有的资料都熟悉一遍,估计半个月也搞不定,但是程序也不得不继续下去了,项目总不能没有一点进展,老板会没有耐心。加油。     /*************************************************************/ 2013年是移动互联网的元年,移动互联网大大提高了我们工作和生活的效率。  罗辑思维用互联网思维网络了大量的会员,最近又在召集用互联网思维来吃霸王餐。  我们不需要那么牛气哄哄,互联网思维既然能够解决这样的大事,那小事当然更没问题。  利用互联网思维做一个晨型人,也应该不是一件难事吧。  操作模式如下:申请一个微信公众号,分享作为晨型人一天的收获。  以及在遇到困难的时候,如果克服自己,解决问题。  如果有兴趣,扫一扫下面的公众号 吧,让我们一起轻松的做一个快乐的晨型人。 
  • 热度 15
    2014-1-17 05:57
    1842 次阅读|
    0 个评论
      发送ECAN数据: void sendECAN(mID *message) {  unsigned long word0=0; //合成帧的前三个字  unsigned long word1=0;  unsigned long word2=0; //判断帧类型,是扩展帧,则前三个字定义不同,本例中为扩展帧格式  if(message-frame_type==CAN_FRAME_EXT)  {   word0=(message-id 0x1FFC0000) 16; //取帧的最高11位,作为第一个字,右移16位,放到word1   word0=word0+0x0003; //这里是拓展帧,SRR和IDE都设置为1   word1=(message-id 0x0003FFC0) 6; //取得6~17位一共12位   word2=(message-id 0x0000003F) 10; //取最后6位,放到字头  }  else  {   word0=((message-id 0x000007FF) 2); //这里是标准,SRR和IDE都设置为0  }    if(message-message_type==CAN_MSG_RTR)  {   if(message-frame_type==CAN_FRAME_EXT) //根据帧类型,将远程帧的位置设置为1,表示发送的是远程帧    word2=word2 | 0x0200;   else    word0=word0 | 0x0002;    //远程帧不需要跟数据,所以只需要发送头三个字就行了。FILTER4:0这5个位寄存器自动填充。   ecan1msgBuf =word0;   ecan1msgBuf =word1;   ecan1msgBuf =word2;  }  else  {   word2=word2+(message-data_length 0x0F); //如果是数据帧,先将数据长度在WORD2中写入。   ecan1msgBuf =word0;   ecan1msgBuf =word1;   ecan1msgBuf =word2;   ecan1msgBuf =((message-data 8) + message-data ); //继续填入数据域   ecan1msgBuf =((message-data 8) + message-data );   ecan1msgBuf =((message-data 8) + message-data );   ecan1msgBuf =((message-data 8) + message-data );  }  C1TR01CONbits.TXREQ0=1; //设置该位,请求发送一个帧。 }   在主循环中查找,如果状态为缓存满了,则开始读取。 读取的函数如下:   接收ECAN数据:   /****************************************************************************** * * Function: rxECAN * Description: moves the message from the DMA memory to RAM * * Arguments: *message: a pointer to the message structure in RAM * that will store the message. * Author: Jatinder Gharoo * * ******************************************************************************/ void rxECAN(mID *message) {  unsigned int ide=0;  unsigned int rtr=0;  unsigned long id=0; //先判断帧是标准的还是扩展帧,次位都定义在word0的最后一位的位置  ide=ecan1msgBuf 0x0001;  if(ide==0) //如果是标准帧,判断是远程帧还是数据帧  {   message-id=(ecan1msgBuf 0x1FFC) 2; //将ID读出来   message-frame_type=CAN_FRAME_STD; //为标准帧,将帧类型设置   rtr=ecan1msgBuf 0x0002; //将远程帧还是数据帧的标志读出来。  }  else  {   id=ecan1msgBuf 0x1FFC; //将11位读出来   message-id=id 16; //放到ID号的头。   id=ecan1msgBuf 0x0FFF;//读WORD1,   message-id=message-id+(id 6); //和刚刚读出来的组在一起   id=(ecan1msgBuf 0xFC00) 10; //继续读WORD2中的ID   message-id=message-id+id; //获取到完整的ID   message-frame_type=CAN_FRAME_EXT; //设置读取到的帧为拓展帧   rtr=ecan1msgBuf 0x0200;//将远程的标志设置好  }  if(rtr==1) //如果是远程帧,设置结构体消息类型为远程帧类型。  {   message-message_type=CAN_MSG_RTR;  }  else//如果是数据帧,则开始读数据  {   message-message_type=CAN_MSG_DATA; //类型设置为数据帧   message-data =(unsigned char)ecan1msgBuf ;//开始读数据,从BYTE0开始   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8); //读高8位,作为BYTE1,保存到结构体数据存储1位置。   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data =(unsigned char)ecan1msgBuf ;   message-data =(unsigned char)((ecan1msgBuf 0xFF00) 8);   message-data_length=(unsigned char)(ecan1msgBuf 0x000F); //获取数据长度,继续保存到结构体中  }  clearRxFlags(message-buffer); //按照BUFFER号,以及在接收时硬件设置的BUFFER满标志读取,如果是BUFFER1,则把1清空。这里一共用到三个BUFFER,进行三次判断。 }   然后将收到的数据在液晶上显示出来。   ECAN的中断服务程序 void __attribute__((interrupt,no_auto_psv))_C1Interrupt(void) {     if(C1INTFbits.RBIF) //中断来自已经收到一个存到BUFFER中的数据。     {      if(C1RXFUL1bits.RXFUL1) //如果传送来的数据保存在BUFFER1中      {    canRxMessage.buffer_status=CAN_BUF_FULL; //将这个状态设置给结构体,主程序中将通过这个标志来读BUFFER到RAM中。    canRxMessage.buffer=1; //告诉主程序BUFFER满还不行,还要告诉主程序读取的路径,为BUFFER1   }     else if(C1RXFUL1bits.RXFUL2)   {    canRxMessage.buffer_status=CAN_BUF_FULL;    canRxMessage.buffer=2;   }     else if(C1RXFUL1bits.RXFUL3)   {    canRxMessage.buffer_status=CAN_BUF_FULL;    canRxMessage.buffer=3;   }   else;   C1INTFbits.RBIF = 0; //接收标志要清空  }  else if(C1INTFbits.TBIF) //如果是发送数据产生的中断     {      puts_ecanTx(canTxMessage); //将发送的数据在液晶上显示出来   C1INTFbits.TBIF = 0; //发送标志清空  }  else;  IFS2bits.C1IF=0; //同时要将ECAN中断标志情况。 }   问题点: 用到了DMA么?这里可以看到,在中断服务程序中只设置了标志,帧是读入到了DMA中,通知主程序在一次大循环后来读出DMA的值。   收到的数据没有MASK和FILTER?:在ECAN初始化函数中已经设置了MASK和FILTER,本例子中,标准模式,每位都需要比较,FILTER的ID是0x123,ID数据不对,则不会将数据读进来,这个是经过硬件处理的,不需要人工干预。          
  • 热度 14
    2014-1-16 06:58
    5470 次阅读|
    0 个评论
    12月份在登陆官网的时候发现更新了MPLAB IDE,安装MPLABX+XC16,一番手忙脚乱,HELP文档多次后终于新建 新的MPLAB X+XC16编译器界面比之前好看了不少,按照向导新建工程,编写测试程序,编译,仿真调试,编程,和之前的IDE还是有一定的兼容,花了一天的时间终于搞定。 实际上是很划算的,使用了几天以后发现新的IDE确实有了很多以人为本的功能,包括颜色区分以及窗口的排布方面。 新建工程→选择新建一个标准的嵌入式工程→选择PIC24HJ128GP506芯片→选择工具为KIT3→选择C30编译器,然后就OK了,然后新建一个源码文件,选择文件类型为带STDIO的C文件。 现在问题来了,选择最新下载的X16的编译器没法找到,然后按照help文档,在TOOLS-OPRATION里面可以设置,把BIN添加进去就可以了,然后关掉软件重开,新建一个工程,OK,可以了。新建文件的时候,应该要选择嵌入式的文件,里面可以选择X16类型的,然后尝试一下编写程序,发现惊喜: 自动识别错误和自动组织程序的框架,比如空格。 #include "xc.h" int main(void) {     unsigned char i;   // i=0;     for(i=0;i10;i++)     {         Nop();     }     return 0; } 配置位,配置位的配置按照下面的步骤: Step 1 opens the Configuration Bits window. Step 2 reviews every setting. Step 3 generates the pragmas that can implement the settings you have chosen. Step 4 copies the code from this window to a source file of your choosing. 需要将代码拷贝到main函数前面,而不能直接在MPLABX里面设置。配置完后生成的代码如下: 调试代码: 断点 设置CTRL+F8设置,按一次取消。 可以设置断点位置为事件,地址,行号,数据等 还可以设置断点序列 还可以断点相与 还可以测试两个断点之间的时间,还可以在DASHBOARD里面查看断点使用情况。 单步运行代码 可以查看器件MEMORy 查看MEMORY 改变MEMORY的值 如果将外设的模块加进去,发现弹出错误: 具体是: 这就奇怪了,明明安装文件里面有这个头文件啊,用source insight打开后,发现 : 定义了这颗芯片,会自动将这个头文件加入进去。 疑问解决了,如果main函数的C文件里面添加了该外设的头文件,才会显示文件里面的亮色。如 #includei2c.h 并且所选的芯片自动添加进去的头文件里面包含了 #define _MI2C1IF IFS1bits.MI2C1IF 这条,则开始在在I2C的头文件中显示亮色,亮色部分表示定义有效: 而这个头文件的宏定义: #if defined(__dsPIC30F__) #include p30Fxxxx.h #elif defined(__dsPIC33F__) #include p33Fxxxx.h #elif defined(__PIC24H__) #include p24Hxxxx.h #elif defined(__PIC24E__) #include p24Exxxx.h #elif defined(__dsPIC33E__) #include p33Exxxx.h #endif 应该是在编译器中自动进行了判断的,比如,所有系列的芯片都要用到的头文件,则不会有这个宏定义的说明。 从上面可以看出: 在IDE中选择芯片,编译器会自动添加一个头文件,头文件里面会定义芯片的资源,如果有这个资源,则要看C函数中是否包括了该头文件,如果头文件包括了,用亮色来显示该资源可用。 这里还有一个小工具可以用,就是: 可以在头文件和源文件中进行切换,但是要注意,这个文件名必须是相同的。