我是靠谱客的博主 虚心银耳汤,最近开发中收集的这篇文章主要介绍ZigBee串口的运行流程以及修改,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

从主函数main开始

void HalDriverInit (void)
{
  /* TIMER */
#if (defined HAL_TIMER) && (HAL_TIMER == TRUE)
  #error "The hal timer driver module is removed."
#endif


  /* ADC */
#if (defined HAL_ADC) && (HAL_ADC == TRUE)
  HalAdcInit();
#endif


  /* DMA */
#if (defined HAL_DMA) && (HAL_DMA == TRUE)
  // Must be called before the init call to any module that uses DMA.
  HalDmaInit();
#endif


  /* AES */
#if (defined HAL_AES) && (HAL_AES == TRUE)
  HalAesInit();
#endif


  /* LCD */
#if (defined HAL_LCD) && (HAL_LCD == TRUE)
  HalLcdInit();
#endif


  /* LED */
#if (defined HAL_LED) && (HAL_LED == TRUE)
  HalLedInit();
#endif


  /* UART */
#if (defined HAL_UART) && (HAL_UART == TRUE)
  HalUARTInit();
#endif


  /* KEY */
#if (defined HAL_KEY) && (HAL_KEY == TRUE)
  HalKeyInit();
#endif


  /* SPI */
#if (defined HAL_SPI) && (HAL_SPI == TRUE)
  HalSpiInit();
#endif


  /* HID */
#if (defined HAL_HID) && (HAL_HID == TRUE)
  usbHidInit();
#endif
}

hal_uart.c

void HalUARTInit(void)
{
#if HAL_UART_DMA//ZigBee的的串口接收采用的是DMA接收,节省CPU的资源
  HalUARTInitDMA();

#endif
#if HAL_UART_ISR
  HalUARTInitISR();
#endif
#if HAL_UART_USB
  HalUARTInitUSB();
#endif
}

_hal_uart_dma.c

static void HalUARTInitDMA(void)
{
  halDMADesc_t *ch;


  P2DIR &= ~P2DIR_PRIPO;
  P2DIR |= HAL_UART_PRIPO;


#if (HAL_UART_DMA == 1)
  PERCFG &= ~HAL_UART_PERCFG_BIT;    // Set UART0 I/O to Alt. 1 location on P0.
#else
  PERCFG |= HAL_UART_PERCFG_BIT;     // Set UART1 I/O to Alt. 2 location on P1.
#endif
  PxSEL  |= HAL_UART_Px_RX_TX;       // Enable Tx and Rx on P1.
  ADCCFG &= ~HAL_UART_Px_RX_TX;      // Make sure ADC doesnt use this.
  UxCSR = CSR_MODE;                  // Mode is UART Mode.
  UxUCR = UCR_FLUSH;                 // Flush it.



  // Setup Tx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );


  // The start address of the destination.
  HAL_DMA_SET_DEST( ch, DMA_UDBUF );


  // Using the length field to determine how many bytes to transfer.
  HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );


  // One byte is transferred each time.
  HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );


  // The bytes are transferred 1-by-1 on Tx Complete trigger.
  HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
  HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );


  // The source address is incremented by 1 byte after each transfer.
  HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );


  // The destination address is constant - the Tx Data Buffer.
  HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );


  // The DMA Tx done is serviced by ISR in order to maintain full thruput.
  HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_ENABLE );


  // Xfer all 8 bits of a byte xfer.
  HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );


  // DMA has highest priority for memory access.
  HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );


  // Setup Rx by DMA.
  ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );


  // The start address of the source.
  HAL_DMA_SET_SOURCE( ch, DMA_UDBUF );


  // Using the length field to determine how many bytes to transfer.
  HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );


  /* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx.
   * The byte after the Rx Data Buffer is the Baud Cfg Register,
   * which always has a known value. So init Rx buffer to inverse of that
   * known value. DMA word xfer will flip the bytes, so every valid Rx byte
   * in the Rx buffer will be preceded by a DMA_PAD char equal to the
   * Baud Cfg Register value.
   */
  HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD );


  // The bytes are transferred 1-by-1 on Rx Complete trigger.
  HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE_REPEATED );
  HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_RX );


  // The source address is constant - the Rx Data Buffer.
  HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 );


  // The destination address is incremented by 1 word after each transfer.
  HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 );
  HAL_DMA_SET_DEST( ch, dmaCfg.rxBuf );
  HAL_DMA_SET_LEN( ch, HAL_UART_DMA_RX_MAX );


  // The DMA is to be polled and shall not issue an IRQ upon completion.
  HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );


  // Xfer all 8 bits of a byte xfer.
  HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );


  // DMA has highest priority for memory access.
  HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
}



串口DMA的引脚不是固定的,根据不同的硬件引脚来配置不同的模式。


串口的初始化包括波特率等的初始化

从main函数开始


osal_init_system();//初始化操作系统


  // Initialize the system tasks.
  osalInitTasks();


 SampleApp_Init( taskID );

MT_UART.C

这样一路goto到达波特率的初始化

void SampleApp_Init( uint8 task_id )
{
  SampleApp_TaskID = task_id;
  SampleApp_NwkState = DEV_INIT;
  SampleApp_TransID = 0;
  
  MT_UartInit();//串口初始化
  MT_UartRegisterTaskID(task_id);//登记任务号
  HalUARTWrite(0,"Hello Worldn",12); //(串口0,'字符',字符个数。)
  
  // Device hardware initialization can be added here or in main() (Zmain.c).
  // If the hardware is application specific - add it here.
  // If the hardware is other parts of the device add it in main().


 #if defined ( BUILD_ALL_DEVICES )
  // The "Demo" target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START
  // We are looking at a jumper (defined in SampleAppHw.c) to be jumpered
  // together - if they are - we will start up a coordinator. Otherwise,
  // the device will start as a router.
  if ( readCoordinatorJumper() )
    zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
  else
    zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES


#if defined ( HOLD_AUTO_START )
  // HOLD_AUTO_START is a compile option that will surpress ZDApp
  //  from starting the device and wait for the application to
  //  start the device.
  ZDOInitDevice(0);
#endif


  // Setup for the periodic message's destination address
  // Broadcast to everyone
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
  
  SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
  SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Periodic_DstAddr.addr.shortAddr = a;


  // Setup for the flash command's destination address - Group 1
  SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup;
  SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;


  // Fill out the endpoint description.
  SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT;
  SampleApp_epDesc.task_id = &SampleApp_TaskID;
  SampleApp_epDesc.simpleDesc
            = (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;
  SampleApp_epDesc.latencyReq = noLatencyReqs;


  // Register the endpoint description with the AF
  afRegister( &SampleApp_epDesc );


  // Register for all key events - This app will handle all key events
  RegisterForKeys( SampleApp_TaskID );


  // By default, all devices start out in Group 1
  SampleApp_Group.ID = 0x0001;
  osal_memcpy( SampleApp_Group.name, "Group 1", 7  );
  aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );


#if defined ( LCD_SUPPORTED )
  HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 );
#endif
}

在这里可以进行波特率的修改

#if !defined MT_UART_DEFAULT_BAUDRATE
#define MT_UART_DEFAULT_BAUDRATE         HAL_UART_BR_115200//HAL_UART_BR_38400
#endif

#define HAL_UART_BR_9600   0x00
#define HAL_UART_BR_19200  0x01
#define HAL_UART_BR_38400  0x02
#define HAL_UART_BR_57600  0x03
#define HAL_UART_BR_115200 0x04

void MT_UartInit ()
{
  halUARTCfg_t uartConfig;


  /* Initialize APP ID */
  App_TaskID = 0;


  /* UART Configuration */
  uartConfig.configured           = TRUE;
  uartConfig.baudRate             = MT_UART_DEFAULT_BAUDRATE;
  uartConfig.flowControl          = MT_UART_DEFAULT_OVERFLOW;
  uartConfig.flowControlThreshold = MT_UART_DEFAULT_THRESHOLD;
  uartConfig.rx.maxBufSize        = MT_UART_DEFAULT_MAX_RX_BUFF;
  uartConfig.tx.maxBufSize        = MT_UART_DEFAULT_MAX_TX_BUFF;
  uartConfig.idleTimeout          = MT_UART_DEFAULT_IDLE_TIMEOUT;
  uartConfig.intEnable            = TRUE;
#if defined (ZTOOL_P1) || defined (ZTOOL_P2)
  uartConfig.callBackFunc         = MT_UartProcessZToolData;

我们定义的这个就用MT_UartProcessZToolData进行串口数据的接受
#elif defined (ZAPP_P1) || defined (ZAPP_P2)
  uartConfig.callBackFunc         = MT_UartProcessZAppData;
#else
  uartConfig.callBackFunc         = NULL;
#endif


  /* Start UART */
#if defined (MT_UART_DEFAULT_PORT)
  HalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig);
#else
  /* Silence IAR compiler warning */
  (void)uartConfig;
#endif


  /* Initialize for ZApp */
#if defined (ZAPP_P1) || defined (ZAPP_P2)
  /* Default max bytes that ZAPP can take */
  MT_UartMaxZAppBufLen  = 1;
  MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;
#endif


}

//经过网蜂的修改这是一个非常易容的串口接收代码

void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
/*  uint8  ch;
  uint8  bytesInRxBuffer;
  
  (void)event;  // Intentionally unreferenced parameter*/
  uint8 flag=0,i,j=0;   //flag是判断有没有收到数据,j记录数据长度
  uint8 buf[128];     //串口buffer最大缓冲默认是128,我们这里用128.
  (void)event;        // Intentionally unreferenced parameter  


  while (Hal_UART_RxBufLen(port)) //检测串口数据是否接收完成


  {
    HalUARTRead (port,&buf[j], 1);  //把数据接收放到buf中读取的时候回调用DMA进行读取数据
    j++;                           //记录字符数
    flag=1;                         //已经从串口接收到信息
  } 


  if(flag==1)       //已经从串口接收到信息


  {     /* Allocate memory for the data */
   //分配内存空间,为机构体内容+数据内容+1个记录长度的数据
   pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof  
          ( mtOSALSerialData_t )+j+1);
  //事件号用原来的CMD_SERIAL_MSG
  pMsg->hdr.event = CMD_SERIAL_MSG;
  pMsg->msg = (uint8*)(pMsg+1);  // 把数据定位到结构体数据部分
  pMsg->msg [0]= j;              //给上层的数据第一个是长度
  for(i=0;i<j;i++)                //从第二个开始记录数据 
  pMsg->msg [i+1]= buf[i];   
  osal_msg_send( App_TaskID, (byte *)pMsg );  //登记任务,发往上层发送到上层就是应用层
  /* deallocate the msg */
  osal_msg_deallocate ( (uint8 *)pMsg );      //释放内存
  }

转跳到数据发送的应用层

uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
  afIncomingMSGPacket_t *MSGpkt;
  (void)task_id;  // Intentionally unreferenced parameter


  if ( events & SYS_EVENT_MSG )
  {
    MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    while ( MSGpkt )
    {
      switch ( MSGpkt->hdr.event )
      {
        case CMD_SERIAL_MSG://新添加接收串口信息
          SampleApp_SerialCMD((mtOSALSerialData_t *)MSGpkt);//串口一旦来了数据触发这个函数,稍后转跳到这个函数

          break;
        // Received when a key is pressed
        case KEY_CHANGE://按键触发
          SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
          break;


        // Received when a messages is received (OTA) for this endpoint
        case AF_INCOMING_MSG_CMD://有无线数据到来
          SampleApp_MessageMSGCB( MSGpkt );
          break;


        // Received whenever the device changes state in the network
        case ZDO_STATE_CHANGE://当网络状态改变,如从未连接上到连上网络
          SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
          if ( (SampleApp_NwkState == DEV_ZB_COORD)//协调器、路由器、或者终端都执行
              || (SampleApp_NwkState == DEV_ROUTER)
              || (SampleApp_NwkState == DEV_END_DEVICE) )
          {
            // Start sending the periodic message in a regular interval.//打开定时器
            osal_start_timerEx( SampleApp_TaskID,//任务ID号
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT,//同一个任务下可以有多个事件,这个是事件的号码。事件号码16位必须只占1位,所以只能定义16个事件
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );//时间
            osal_start_timerEx( SampleApp_TaskID,//任务ID号
                              SAMPLEAPP_SEND_PERIODIC_MSG_EVT2,//同一个任务下可以有多个事件,这个是事件的号码。事件号码16位必须只占1位,所以只能定义16个事件
                              SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );//时间
          }
          else
          {
            // Device is no longer in the network
          }
          break;


        default:
          break;
      }


      // Release the memory
      osal_msg_deallocate( (uint8 *)MSGpkt );


      // Next - if one is available
      MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
    }


    // return unprocessed events
    return (events ^ SYS_EVENT_MSG);
  }


  // Send a message out - This event is generated by a timer
  //  (setup in SampleApp_Init()).
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )//周期性发数
  {
    // Send the periodic message
    SampleApp_SendPeriodicMessage();//周期性发送函数


    // Setup to send message again in normal period (+ a little jitter)
 //   osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
   //     (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );


    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
  }
  if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT2 )//周期性发数
  {
    // Send the periodic message
    //SampleApp_SendPeriodicMessage();//周期性发送函数


    // Setup to send message again in normal period (+ a little jitter)
 //   osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
   //     (SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );


    // return unprocessed events
    return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT2);
  }
  SAMPLEAPP_SEND_PERIODIC_MSG_EVT2


  // Discard unknown events
  return 0;
}

串口来了数据会触发这个函数

void SampleApp_SerialCMD(mtOSALSerialData_t *cmdMsg)
{
  uint8 i,len,*str=NULL;     //len有用数据长度
  str=cmdMsg->msg;          //指向数据开头
  len=*str;                 //msg里的第1个字节代表后面的数据长度


  /********打印出串口接收到的数据,用于提示*********/


  for(i=1;i<=len;i++)
  HalUARTWrite(0,str+i,1 ); 
  HalUARTWrite(0,"n",1 );//换行  


  /*******发送出去***参考网蜂 1小时无线数据传输教程*********/


  if ( AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,//无线模块的发送
                   SAMPLEAPP_COM_CLUSTERID,//自己定义一个
                   len+1,                  // 数据长度         
                            str,                     //数据内容
                   &SampleApp_TransID, 
                   AF_DISCV_ROUTE,
                   AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )
                    {
                    }
  else
  {
  // Error occurred in request to send.
  } 
}

通过串口发送到PC机上,代码其实很 简单。

 for(i=1;i<=len;i++)
  HalUARTWrite(0,str+i,1 ); 
  HalUARTWrite(0,"n",1 );//换行  

这么几句话就完成了串口发送数据到PC机的任务

到这里串口相关的问题就讨论到这里


最后

以上就是虚心银耳汤为你收集整理的ZigBee串口的运行流程以及修改的全部内容,希望文章能够帮你解决ZigBee串口的运行流程以及修改所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部