TIMAC 开发随笔二:CC2530的串口操作

TIMAC 开发随笔 二 : CC2530的串口操作

引用请注明出处!!我的邮箱qinxiaoyu@163.com

本人身在山西太原,欢迎各位联系哦。。。

        其实说CC2530串口的文章已经很多了,有的文章说的特别的详细。我在一开始调串口的时候也参考了很多网上的文章,他们都给了我很大的帮助!这里我说的串口操作也是走的其中的一条路子,那么就是移植ZStack的部分串口软件来做开发。

        先说说我为什么特别钟情于串口的操作,在一上来弄TIMAC的第一步就是先打通串口部分。

        1.串口基本上是我们最常用的接口了。在后续的开发中,大部分的通讯都是依靠串口来完成的。

        2.串口工具的易取得性。做软件开发的,SPI转USB的不多,UART转USB的小转换板总是特别多的。

        3.方便观察软件流程。其实这里也不一定非要使用串口,要是有其他好的接口也可以使用。有人说过,读懂一段代码最难的就是专业术语。但是我感觉,软件的流程,数据的走向,也都是很重要的部分。

        IAR的IDE并没有提供很好的输出设备(当然,也有可能是我还不知道怎么使用)。当我们的代码运行的时候,我们不可能只依靠一些断点来判断程序的走向,这样效率太低下了。所以,我们必须引入一种更好的调试方式。那么就是输出打印信息!就像linux下的打印信息一样,我们可以随时掌握程序的走向!

         开始说串口的操作了,这里我还会把我的打印管理贴出来供大家参考一下。这套管理方法学自于CSR的蓝牙软件,优点是管理方便;缺点是会占有比较多的code空间。不过我们的软件不是很大,只有50多kb,而flash却有256k,够我们挥霍的了。

       

1.选择uart的读取数据的方式:

         CC2530给我们提供了2种读取串口数据的方式,一种是中断式的(ISR),一种是DMA式的。CC2530的文档上明确的告诉了我们,在使用ISR式并且串口速率在115200时,当RF数据繁忙的时候,可能会有不可预料的问题。我们需要至少115200的串口速率,所以就果断放弃ISR方式。

          在这里,我们需要使能CC2530的DMA.。

/* Set to TRUE enable DMA usage, FALSE disable it */
#ifndef HAL_DMA
#define HAL_DMA TRUE
#endif

        将原来的FALSE改成TRUE就可以了。

2.使能UART:

/* Set to TRUE enable UART usage, FALSE disable it */
#ifndef HAL_UART
#if (defined ZAPP_P1) || (defined ZAPP_P2) || (defined ZTOOL_P1) || (defined ZTOOL_P2)
#define HAL_UART TRUE
#else
#define HAL_UART FALSE
#endif
#endif

      在这里,我直接将我的设备设置成了ZAPP_P1设备。在IDE的project->option->C/C++连接器中的宏定义中直接定义宏ZAPP_P1。这样就将HAL_UART设置成了TRUE。

3.设置UART使用DMA模式:

#ifndef HAL_UART_DMA
#if HAL_DMA
#if (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_DMA  2
#else
#define HAL_UART_DMA  1
#endif
#else
#define HAL_UART_DMA  0
#endif
#endif
      我们在上一步设置宏的时候定义了ZAPP_P1,这样#define HAL_UART_DMA  2是有效的。我们刚好需要UART1来做串口,定义成了2,刚好对应的就是UART1。
#ifndef HAL_UART_ISR
#if HAL_UART_DMA           // Default preference for DMA over ISR.
#define HAL_UART_ISR  0
#elif (defined ZAPP_P2) || (defined ZTOOL_P2)
#define HAL_UART_ISR  2
#else
#define HAL_UART_ISR  1
#endif
#endif
      ISR模式被设置成了0,在后续的编译时,ISR方式的函数将不会被编译。

4.设置串口参数(这一段函数我们使用了ZStack的MT_UART中的代码)

#define MT_UART_ZAPP_RX_READY           0x01
#define UartDefaultRxLen		50
#define UartDefaultTxLen		30
#define UartDefaultIdleTimeOut	        200

void UartSetNormalConfig(uint8 port)
{
    halUARTCfg_t UartConifg;

    UartConifg.configured            = TRUE;
    UartConifg.baudRate              = HAL_UART_BR_115200;      //串口波特率
    UartConifg.flowControl           = HAL_UART_FLOW_OFF;       //流控开关
    UartConifg.flowControlThreshold  = 0;
    UartConifg.rx.maxBufSize         = UartDefaultRxLen;        //rxbuf的大小
    UartConifg.tx.maxBufSize         = UartDefaultTxLen;        //txbuf的大小
    UartConifg.idleTimeout           = UartDefaultIdleTimeOut;  //串口超时时间
    UartConifg.intEnable             = TRUE;                    //中断使能
    UartConifg.callBackFunc          = MT_UartProcessZAppData;  //串口回调函数
    HalUARTOpen(port,&UartConifg);                              //设置串口
    MT_UartMaxZAppBufLen  = UartDefaultRxLen;
    MT_UartZAppRxStatus   = MT_UART_ZAPP_RX_READY;
}     
5.串口回调函数(串口数据就在这个位置被读取出来)

void MT_UartProcessZAppData ( uint8 port, uint8 event )
{

	osal_event_hdr_t  *msg_ptr;
	uint16 length = 0;
	uint16 rxBufLen  = Hal_UART_RxBufLen(MT_UART_DEFAULT_PORT);

	/*
	If maxZAppBufferLength is 0 or larger than current length
	the entire length of the current buffer is returned.
	*/
	if ((MT_UartMaxZAppBufLen != 0) && (MT_UartMaxZAppBufLen <= rxBufLen))
	{
		length = MT_UartMaxZAppBufLen;
	}
	else
	{
		length = rxBufLen;
	}

	/* Verify events */
	if (event == HAL_UART_TX_FULL)
	{
		// Do something when TX if full
		return;
	}

	if (event & ( HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT))
	{
		if ( Hal_TaskID )
		{
			/*
			If Application is ready to receive and there is something
			in the Rx buffer then send it up
			*/
			if ((MT_UartZAppRxStatus == MT_UART_ZAPP_RX_READY ) && (length != 0))
			{
				/* Disable App flow control until it processes the current data */
				MT_UartAppFlowControl (MT_UART_ZAPP_RX_NOT_READY);

				/* 2 more bytes are added, 1 for CMD type, other for length */
				msg_ptr = (osal_event_hdr_t *)osal_msg_allocate( length + sizeof(osal_event_hdr_t) );
				if ( msg_ptr )
				{
					msg_ptr->event = HAL_UART_PROCESS_EVENT;
					msg_ptr->status = length;

					/* Read the data of Rx buffer */
                                        /*!!!!!!这里读取串口中的数据!!!!!*/
                                        HalUARTRead( MT_UART_DEFAULT_PORT, (uint8 *)(msg_ptr + 1), length );
					MT_UartZAppRxStatus	= MT_UART_ZAPP_RX_READY;
				}
			}
		}
	}
}
void MT_UartAppFlowControl ( bool status )
{
    /* Make sure only update if needed */
    if (status != MT_UartZAppRxStatus )
    {
        MT_UartZAppRxStatus = status;
    }

    /* App is ready to read again, ProcessZAppData have to be triggered too */
    if (status == MT_UART_ZAPP_RX_READY)
    {
        MT_UartProcessZAppData (MT_UART_DEFAULT_PORT, HAL_UART_RX_TIMEOUT );
    }
}

6.串口数据发送函数(现在已经写成了多参数的debug函数,等同于printf,zprintf函数等)

新建一个文件,起名为debug.c

void DEBUG(uint8 *fmt ,...)
{
#ifdef DEBUG_ENABLED
	va_list	arg_ptr;
	uint8	LocalText[64];
	uint8 	cnt;
	uint8	m;
	for(cnt=0 ; cnt<64 ; cnt++) 
	{
		LocalText[cnt] = 0x00;
	}

	va_start(arg_ptr, fmt);
	vsprintf(LocalText, fmt, arg_ptr);
	va_end(arg_ptr);
	for(m=0 ; m<64 ; m++) 
	{
		if(LocalText[m]==0x00)
		{
			break;
		}
	}
	HalUARTWrite(HAL_UART_PORT_1,LocalText,m);
#else
;
#endif	
}
7.串口debug宏定义

可以新建一个debug.h文件,在debug.h文件中定义下列的宏。以按键debug为例:

#ifdef	DEBUG_ENABLED
#define DEBUG_HAL_KEY_D   //按键debug
#define DEBUG_MSA_D       
#define DEBUG_MAC_PIB_D
#define DEBUG_MAC_RADIO_D
#define DEBUG_MSA_MAIN_D
#endif

在hal_key.c中添加如下的语句:

#include “debug.h”
#ifdef DEBUG_HAL_KEY_D
#define DEBUG_HAL_KEY_STR(X,Y)			DEBUG_STRING(X, Y)
#define DEBUG_HAL_KEY(X,...) 			DEBUG(X,##__VA_ARGS__)
#else
#define DEBUG_HAL_KEY_STR(X,Y)
#define DEBUG_HAL_KEY(X,...)	
#endif
在hal_key.c文件中可以如下使用DEBUG_HAL_KEY()函数,如:

void HalKeyPoll (void)
{
	uint8 keys = 0;

	if ((HAL_KEY_JOY_MOVE_PORT & HAL_KEY_JOY_MOVE_BIT))  /* Key is active HIGH */
	{
		keys = halGetJoyKeyInput();
		DEBUG_HAL_KEY("HAL KEY::halGetJoyKeyInput=%d\r\n",keys);
	}

	if (!HAL_PUSH_BUTTON1())
	{
		DEBUG_HAL_KEY("HAL KEY::HalKeyPoll HAL_PUSH_BUTTON1\r\n");
		keys |= HAL_KEY_SW_6;
	}
	if (!HAL_PUSH_BUTTON2())
	{
		DEBUG_HAL_KEY("HAL KEY::HalKeyPoll HAL_PUSH_BUTTON2\r\n");
		keys |= HAL_KEY_SW_7;
	}
	/* If interrupts are not enabled, previous key status and current key status
	* are compared to find out if a key has changed status.*/
	if (!Hal_KeyIntEnable)
	{
		if (keys == halKeySavedKeys)
		{
			/* Exit - since no keys have changed */
			return;
		}
		/* Store the current keys for comparation next time */
		halKeySavedKeys = keys;
	}
	else
	{
		/* Key interrupt handled here */
	}



	/* Invoke Callback if new keys were depressed */
	if (keys && (pHalKeyProcessFunction))
	{
	(pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL);
	}
}
这样在按键1按下,按键2按下,遥控柄按下的情况下,都会有串口数据从串口1输出。


当我们不想debug文件hal_key.c中的内容时,只要将debug.h中的宏

#define DEBUG_HAL_KEY_D
变成

#define xDEBUG_HAL_KEY_D
就不会输出hal_key..c中的debug内容了。


同理,要想关闭整个软件中的debug内容,则只要将

#define DEBUG_ENABLED
变成

#define xDEBUG_ENABLED
整个工程中,串口1就不会有任何的debug输出了。



小结:串口的debug数据的输出对于调试有着非常直观的作用,使用这种方式debug,将大大的降低软件阅读的难度。用上面的方法管理debug的输出,也更加的合理,更加的便于操作!





  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值