ZStack串口操作

来源:互联网 发布:网络男歌手名字大全 编辑:程序博客网 时间:2024/06/04 18:05

对ZStack串口的操作并不复杂,只要在需要的配置串口,打开串口,收发数据即可。 


一、串口的配置和打开


要使用串口,首先需要对串口进行配置。在hal_uart.h中,我们可以找到halUARTCfg_t结构体用于配置串口:
typedef struct
{
  bool                configured;
  uint8               baudRate;
  bool                flowControl;
  uint16              flowControlThreshold;
  uint8               idleTimeout;
  halUARTBufControl_t rx;
  halUARTBufControl_t tx;
  bool                intEnable;
  uint32              rxChRvdTime;
  halUARTCBack_t      callBackFunc;
}halUARTCfg_t;
在这个结构体中,定义了串口正常工作需要的一些数据,如波特率等,同时也包含了一个重要的函数指针  halUARTCBack_t      callBackFunc这个稍后再说。
举一个实例:
void UARTService_Init(void)
{
  halUARTCfg_t uartConfig;
  
  uartConfig.configured           = TRUE;              // 2x30 don't care - see uart driver.
  uartConfig.baudRate             = HAL_UART_BR_38400;
  uartConfig.flowControl          = FALSE;
  uartConfig.flowControlThreshold = 256;  // 2x30 don't care - see uart driver.
  uartConfig.rx.maxBufSize        = 70;   // 2x30 don't care - see uart driver.
  uartConfig.tx.maxBufSize        = 256;  // 2x30 don't care - see uart driver.
  uartConfig.idleTimeout          = 6;    // 2x30 don't care - see uart driver.
  uartConfig.intEnable            = TRUE;              // 2x30 don't care - see uart driver.
  uartConfig.callBackFunc         = UARTService_ReceiveCallBack;
  
  HalUARTOpen(UART_CONTROLLER_PORT,&uartConfig);
  HalUARTOpen(UART_WIFI_PORT,&uartConfig); 
}
在配置好串口之后,调用uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config)打开串口就可以正常使用了。HalUARTOpen的有两个参数,前一个为串口号,后一个为串口配置的结构体,之前已经叙述过了。CC2530配套的ZStack-CC2530-2.3.0-1.4.0,也就是目前我使用的版本,定义了2个串口,可以根据需要使用。
/* Ports */
#define HAL_UART_PORT_1   0x01
#define HAL_UART_PORT_MAX 0x02
二、串口的读写操作
简单来说,写串口调用uint16 HalUARTWrite(uint8 port, uint8 *buf, uint16 len),读串口调用uint16 HalUARTRead(uint8 port, uint8 *buf, uint16 len)函数即可(均在hal_uart.c)中定义。
写串口这样操作没有问题,但是读串口的时候就有问题了:我们怎么知道应该在什么时候读串口里的数据呢?
想一想之前在串口配置halUARTCfg_t中,是不是有什么东西我们还没有用到的?对的,有一个函数指针halUARTCBack_t ,先看一下具体定义:
typedef void (*halUARTCBack_t) (uint8 port, uint8 event);
就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。
我先给你一个自定义数据类型的例子。
typedef int* PINT;     //为int* 类型定义了一个PINT的别名
int main()
{
   int x;
   PINT px=&x;    //与int * px=&x;是等价的。PINT类型其实就是int * 类型
   *px=10;        //px就是int*类型的变量  
   return 0;
}
根据注释,应该不难看懂吧!(虽然你可能很少这样定义使用,但以后学习Win32编程时会经常见到的。)
下面我们来看一下函数指针类型的定义及使用:(请与上对照!)
//自行包含头文件
void MyFun(int x);     //此处的申明也可写成:void MyFun( int );
typedef void (*FunType)(int );    //这样只是定义一个函数指针类型
FunType FunP;               //然后用FunType类型来申明全局FunP变量
{
  (void)port;
  (void)config;

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_USB)
  HalUARTOpenUSB(config);
#endif
  
  return HAL_UART_SUCCESS;
}

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_USB)
  HalUARTOpenUSB(config);
#endif
  
  return HAL_UART_SUCCESS;
}

#if (HAL_UART_DMA == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_DMA == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenDMA(config);
#endif
#if (HAL_UART_ISR == 1)
  if (port == HAL_UART_PORT_0)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_ISR == 2)
  if (port == HAL_UART_PORT_1)  HalUARTOpenISR(config);
#endif
#if (HAL_UART_USB)
  HalUARTOpenUSB(config);
#endif
  
  return HAL_UART_SUCCESS;
}
{
 dmaCfg.uartCB = config->callBackFunc;
  // Only supporting subset of baudrate for code size - other is possible.
  HAL_UART_ASSERT((config->baudRate == HAL_UART_BR_9600) ||
                  (config->baudRate == HAL_UART_BR_19200) ||
                  (config->baudRate == HAL_UART_BR_38400) ||
                  (config->baudRate == HAL_UART_BR_57600) ||
                  (config->baudRate == HAL_UART_BR_115200));
  {
    dmaCfg.uartCB(HAL_UART_DMA-1, evt);
  }





(函数指针什么的我也不懂啊,恶补中……稍后继续……)


-----------------------------------------------学习归来的分割线-------------------------------------------------

首先解释一下上面的typedef,之前我理解这个语句是声明了一个函数指针,但是进一步了解之后发现不是这样,而是定义了一个函数指针的类型,解释如下:



由上可以看出halUARTCBack_t是一个函数指针类型,而在之前我给出的配置串口中,有这样一句:

  halUARTCBack_t      callBackFunc;

而在之后给出的串口配置实例中,又有这样一句:

 halUARTCfg_t uartConfig;

 uartConfig.callBackFunc         = UARTService_ReceiveCallBack;

所以,到目前为止,我们是定义了一个halUARTCfg_t类型的函数指针,也就是UARTService_ReceiveCallBack。

(在这里我又纠结了,UARTService_ReceiveCallBack到底是函数还是指针?容我三思……

问题出在函数指针的赋值上 uartConfig.callBackFunc = UARTService_ReceiveCallBack 。很明显等式的左侧是一个函数指针,也就是指向函数的指针,而等式右侧的又是什么呢?也是个指针吗?正确答案是,UARTService_ReceiveCallBack是一个函数(的地址),虽然省去了取地址符&,但它表明的是这个函数的地址,并且能通过大多数编译器的编译。

完整和推荐的写法是 uartConfig.callBackFunc         = &UARTService_ReceiveCallBack;


到这里我们就能明白在配置串口之后,我们能得到一个可以自己定义的函数,用于处理串口的事件。那么下一个问题是,这个函数在什么时候被调用?

在对源代码进行各种查找之后,我得到的结论是:在打开串口(HalUARTOpen)的时候,这个自定义的函数就会被调用。

先看一下HalUARTOpen的定义(在hal_uart.c中):

uint8 HalUARTOpen(uint8 port, halUARTCfg_t *config)

嗯,和DMA、ISR、USB有关,不是很懂,没有找到什么能触发这个函数。

但是不能就这么放弃,继续深挖,找到HalUARTOpenDMA(config)的定义(在hal_uart_dma.c中

static void HalUARTOpenDMA(halUARTCfg_t *config)

这下有了,注意标黑的一句,已经清楚的显示了在这里这个回调函数被调用了。按照同样的思路查找了一下,果然,在ISR中也找到了相应的调用。综上,就可以理解为一旦打开串口,就会调用自己定义的回调函数了O(∩_∩)O~


三、结论


搞清了以上的来龙去脉,我们可以看出,协议栈其实把什么东西都准备好了,你只要自己定义串口的回调函数即可。想实现什么功能,就在回调函数里面添加,剩下的,就是常规的配置串口打开串口和读写串口了,嗯嗯,就是这么简单~

自己动手,丰衣足食~


----------------------------------------------我是补充的分割线-------------------------------------------------

 hal_uart_dma.c中,有这样一个函数static void HalUARTPollDMA(void),在这个函数中,有这么一句话:

 if (evt && (dmaCfg.uartCB != NULL))

可以看出,在有规定的事件发生并且定义了回调函数的情况下,会再次调用回调函数的。

HalUARTPoll->HalUARTPollDMA 这个函数貌似会不停的驱动串口工作,类似于osal_start_system?太底层了,不深究……

原创粉丝点击