引用请注明出处!!我的邮箱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 #endifISR模式被设置成了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的输出,也更加的合理,更加的便于操作!