產品名:ZigBee模塊
型號:ZICM2410 PO-2
廠商:廣州周立功公司代理(美國CEL公司的MeshConnect模塊)
參數:
* 103db鏈路預算;
* 接收靈敏度:-97dbm@ 1.5V
* 發送功率:+6dbm@1.5V
* 3000英尺無障礙傳輸距離
* 最低睡眠電流:<1μA
* 工作電壓:2.1~3.3V
* 接收電流:35mA
* 發送電流:44mA
* 速率:ZigBee (250 kbps)、Turbo(500 kbps)、Premium (1 Mbps)
* 接口類型:SPI(主從)、UART(2路)、I2S/PCM
支持語音傳送:
語音編解碼器支持u律、a律、ADPCM
16條射頻通道
傳送范圍:3000英尺 = 914.4米
支持AES128位加密
ZICM2410 支持的數據通信接口:
UART0\UART1(1M)、I2S、SPI(2M)、GPIO、AD(4路)、IIS
描述:Zigbee網絡基于IEEE 802.15.4國際標準、上層協議為ZigBee協議棧,具有低功
耗,低速率,高可靠性,網絡路由功能強大,自恢復及冗余性能優異等特點,廣泛應用低
數據率監控的各個領域。
ZigBee 物理連接:
ZigBee 模塊是通過串口的形式與微處理器通訊,在LPC11C14 開發板這里是通過 SC16IS752IPW 芯片 轉成 SPI 協議與 微處理器通訊。
ZigBee 模塊(ZICM2410 PO-2) <------串口-----> SC16IS752IPW 芯片 <------SPI-----> LC11C14(ARM M0內核)
從原理圖可以看出,ZigBee模塊的RXD\TXD接在了SC16IS752IPW芯片的RXB\TXB上,
而該芯片的CS\SI\SO\SCLK接在LPC11C14的PIO2_0\PIO2_1\PIO2_2\PIO2_3\PIO3_3上。
說明LPC11C14主控芯片是通過SPI間接與ZigBee模塊通訊,所以我們只需要關注SC16IS752IPW芯片即可,
往該芯片發送數據,ZigBee自然也能收到數據。
數據流向:應用程序 <---讀寫寄存器---> M0的SPI控制器 <---SPI---> SC16IS752IPW <---串口---> ZigBee模塊
程序流程:
1、初始化LPC11C14的SSP1 的GPIO引腳,即 PIO2_0\PIO2_1\PIO2_2\PIO2_3
/* 初始化響應PIO引腳 ssp.c *//* arg1:SSPI0或SSPI1 */
void SPI_IOConfig(uint8_t portNum){if(portNum == 0){/* 此處為通道0的代碼 未貼出 */}else/* port number 1 */{ // 主要設置 SSP1 使之能與 SC16IS752IPW 通信 間接與 ZigBee 通信LPC_SYSCON->PRESETCTRL |= (0x1<<2); // bit2=1 SSP1復位取消 bit2=0 復位SSP1LPC_SYSCON->SYSAHBCLKCTRL |= (1<<18);// 使能SSP1的時鐘LPC_SYSCON->SSP1CLKDIV = 0x02;/* Divided by 2 設置 SSP1 時鐘分頻 48Mhz/2=24Mhz*/LPC_IOCON->PIO2_2 &= ~0x07;/* SSP I/O config */LPC_IOCON->PIO2_2 |= 0x02;/* SSP MISO 將PIO2_2設置為 SSP MISO 模式*/LPC_IOCON->PIO2_3 &= ~0x07;LPC_IOCON->PIO2_3 |= 0x02;/* SSP MOSI 將PIO2_3設置為 SSP MOSI 模式*/LPC_IOCON->PIO2_1 &= ~0x07;LPC_IOCON->PIO2_1 |= 0x02;/* SSP CLK 將PIO2_1設置為 SSP 時鐘 *//* Enable AHB clock to the GPIO domain. */LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // 使能GPIO時鐘 使之產生時鐘LPC_IOCON->PIO2_0 &= ~0x07;/* SSP SSEL is a GPIO pin 設置PIO2_0 作為普通IO管腳功能 *//* port2, bit 0 is set to GPIO output and high */GPIOSetDir( PORT2, 0, 1 ); // 設置為輸出GPIOSetValue( PORT2, 0, 1 ); // 輸出高電平 暫時不使能 該器件 是片選引腳}}
2、初始化 SSP1 寄存器 ssp.c
/* arg1:SSPI0或SSPI1 arg2:傳送位數 arg3:時鐘分配 */
void SPI_Init(uint8_t portNum, uint8_t Bit, uint8_t EvenDiv)
{
uint8_ti, Dummy=Dummy;
if(portNum == 0)
{
/* 此處為通道0的代碼 未貼出 */
}
else
{
LPC_SSP1->CR0 = 0x0700 | (Bit-1); // (Bit-1)=0b0111 8位傳輸 串行時鐘速率、總線類型、數據長度LPC_SSP1->CPSR = EvenDiv; // 時鐘預分頻寄存器 設置為2分頻 -> 48Mhz/2=24Mhzfor ( i = 0; i < SSP_FIFOSIZE; i++ ){Dummy = LPC_SSP1->DR;/* clear the RxFIFO 數據寄存器,讀空則接受FIFO 寫滿則發送 FIFO */}NVIC_EnableIRQ( SSP1_IRQn );// 使能中斷LPC_SSP1->CR1 = SSPCR1_SSE; // SSP1以正常模式與串行總線上的其它設備相互通信。LPC_SSP1->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM; // 中斷觸發條件:接受上溢 接受超時觸發中斷
/* arg1:SSPI0或SSPI1 arg2:數據 */
uint16_t SPI_PutGet(uint8_t portNum, uint16_t SendData){if(portNum == 0){/* 此處為通道0的代碼 未貼出 */}else{/* Move on only if NOT busy and TX FIFO not full. */// SSP1控制器不忙 發送FIFO未滿、發送FIFO不為空 就跳出循環while((LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF);LPC_SSP1->DR = SendData;//寫入數據/* Wait until the Busy bit is cleared. */while(LPC_SSP1->SR & SSPSR_BSY); // 等待總線不忙/* Wait until the Busy bit is cleared */// 等到接受FIFO不為空后跳出循環while((LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE);return LPC_SSP1->DR;// 將數據讀出}}
3.2:寫寄存器時序流程(主要涉及 SCLK、MIOS)
1、片選選中 SC16IS752IPW2、往SPI數據寄存器寫數據2.1 MIOS 寫 SC16IS752IPW THR 寄存器地址寫位(1bit) + SC16IS752IPW THR 寄存器地址(4bit) + 通道選擇(2bit) + X2.2 寫 8位數據3、取消片選/* 往指定的 SC16IS752IPW 寄存器中寫數據 *//* arg1:SSPI0或SSPI1 arg2:SC16IS752IPW 寄存器 arg3:寫入的數據*/void SPI752_RegWrite(uint8_t Channel, uint8_t Reg, uint8_t Data){SPI_UART_CS(0);// 片選選中 SC16IS752IPWSPI_PutGet(1, SPI752_WRITE | (Reg<<3) | (Channel<<1));// 寫寄存器SPI_PutGet(1, Data);// 寫數據SPI_UART_CS(1);// 取消片選}
3.3:讀寄存器時序(主要涉及 SCLK、MIOS、MOIS)
1、片選選中 SC16IS752IPW2、往SPI數據寄存器寫數據2.1 MIOS 寫 SC16IS752IPW RHR 寄存器地址讀位(1bit) + SC16IS752IPW RHR 寄存器地址(4bit) + 通道選擇(2bit) + X2.2 MOSI 讀出 8位數據3、取消片選/* 讀數據 *//* arg1:SSPI0或SSPI1 arg2:SC16IS752IPW 寄存器 */
uint8_t SPI752_RegRead(uint8_t Channel, uint8_t Reg){uint8_trd;SPI_UART_CS(0);// 片選選中 SC16IS752IPWSPI_PutGet(1, SPI752_READ | (Reg<<3) | (Channel<<1)); // 寫寄存器地址rd = SPI_PutGet(1, 0);// 取出數據SPI_UART_CS(1);// 取消片選return rd;}
4、通過SSP1 初始化 SC16IS752IPW
完成SSP1初始化后,就能通過SSP1與 SC16IS752IPW 通訊,,從而初始化該芯片
/******************************************************************************** Function Name : SPI752_Init* Description : Set channel 0 & 1 baud rate. The range is 300-230400 Baud.* The crystal input frequency is 14745600Hz.* The default value of prescaler after reset is divide-by-1.* The format is: 8N1* Input : - Channel : 0 & 1.* - Baud : 300-230400 Baud.* Output : None* Return : None* file :ssp.c*******************************************************************************//* arg1:SSPI0或SSPI1 arg2:波特率 */void SPI752_Init(uint8_t Channel, uint32_t Baud){uint16_trd;// Disable sleep// 設置 數據通信的格式 1 0 1 1 1 1 11 奇葩的設置。。。// 除數鎖存使能 沒有TX間隔條件 奇偶位強制為0 偶數格式 奇偶位 1個停止位 8位SPI752_RegWrite(Channel, SPI752_LCR_RW, 0xBF);// 使能增強型功能rd = SPI752_RegRead(Channel, SPI752_EFR_RW);SPI752_RegWrite(Channel, SPI752_EFR_RW, rd | 0x10);// 設置通信格式為 8位數據傳送 奇葩的設置SPI752_RegWrite(Channel, SPI752_LCR_RW, 0x03);// 使能RHR、THR中斷、使能接收器線狀態中斷、使能modem狀態寄存器中斷rd = SPI752_RegRead(Channel, SPI752_IER_RW);SPI752_RegWrite(Channel, SPI752_IER_RW, rd & (~0x10));// DTR、RTS輸出有效、TCR\TLR使能、使能局部環回模式、使能Xon Any功能 1分頻 奇葩why?rd = SPI752_RegRead(Channel, SPI752_MCR_RW);SPI752_RegWrite(Channel, SPI752_MCR_RW, rd & (~0x80));// Set baud rate & 8N1 format// 設置為 8位 除數所存使能估計為設置波特率準備SPI752_RegWrite(Channel, SPI752_LCR_RW, 0x83);// 設置波特率rd = (14745600/16) / Baud;SPI752_RegWrite(Channel, SPI752_DLL_RW, rd); // 寫入除數最低字節SPI752_RegWrite(Channel, SPI752_DLH_RW, rd>>8); // 寫入除數最高字節// 8位 又來設置通訊格式。。 奇葩。。。SPI752_RegWrite(Channel, SPI752_LCR_RW, 0x03);SPI752_RegRead(Channel, SPI752_RHR_R);// use port3_3 as input event, ZigBee interrupt.// 設置為輸入模式GPIOSetDir(PORT3, 3, 0);// port3_3 interrupt. edge, single trigger, falling edges.// 設置為中斷功能GPIOSetInterrupt(PORT3, 3, 0, 0, 0);// 使能該中斷 當Zig有數據接受時,該中斷被觸發GPIOIntEnable(PORT3, 3);// Set SPI752 RXDx interrupt Enable.//rd = SPI752_RegRead(1, SPI752_IER_RW);//SPI752_RegWrite(Channel, SPI752_IER_RW, rd | 0x01);// 使能RHR中斷又設置了一次 RHR中斷 還能再奇葩點嗎?SPI752_RegWrite(Channel, SPI752_IER_RW, 0x01);// 讀取中斷Why?SPI752_RegRead(Channel, SPI752_RHR_R);}
5、發送1字節數據 (實現了發送1字節就可以發送多字節數據了)
/* 操作M0的SPI控制器 */
/* arg1:SSPI0或SSPI1 arg2:數據 */
uint16_t SPI_PutGet(uint8_t portNum, uint16_t SendData){if(portNum == 0){/* 此處為通道0的代碼 未貼出 */}else{/* Move on only if NOT busy and TX FIFO not full. */// SSP1控制器不忙 發送FIFO未滿、發送FIFO不為空 就跳出循環while((LPC_SSP1->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF);LPC_SSP1->DR = SendData;//寫入數據/* Wait until the Busy bit is cleared. */while(LPC_SSP1->SR & SSPSR_BSY); // 等待總線不忙/* Wait until the Busy bit is cleared */// 等到接受FIFO不為空后跳出循環while((LPC_SSP1->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE);return LPC_SSP1->DR;}}
/******************************************************************************** Function Name : SPI752_PutChar* Description : Use SPI572 channel 0 & 1 send a byte.* Input : - Channel : 0 & 1.* - Ch : 8bit data.* Output : None* Return : None* file :spi_uart.c*******************************************************************************//* arg1:SSPI0或SSPI1 arg2:8位數據 */void SPI752_PutChar(uint8_t Channel, uint8_t Ch){// 等待發送保存寄存器為空while(!(SPI752_RegRead(Channel, SPI752_LSR_R)&0x20));// 往發送保存寄存器寫入數據SPI752_RegWrite(Channel, SPI752_THR_W, Ch);}
6、接受數據 需要借助中斷
6.1:中斷讀取、保存數據
/* 當PIO3 組引腳產生中斷時 此中斷函數被執行 gpio.c */void PIOINT3_IRQHandler(void){/* 此處為其他引腳需要的代碼 未貼出*/
// 判斷是不是 PORT3_3 引腳產生的if(GPIOIntStatus(PORT3, 3)){ZigBee_IRQ_Process(); // 是則說明ZigBee觸發的GPIOIntClear(PORT3, 3); // 清中斷}return;}/* ZigBee 中斷服務程序 讀取數據 spi_uart.c */void ZigBee_IRQ_Process(void){uint8_trd;
/* 此處為0通道的讀取數據的代碼 未貼出*/
rd = SPI752_RegRead(1, SPI752_IIR_R);rd &= 0x3f;if(rd == 0x04) // 判斷是否為RHR中斷 是則讀取數據{// 讀取RHR寄存器值存入數組緩沖區SPI752_rbuf_1[SPI752_rbuf_1_ip] = SPI752_RegRead(1, SPI752_RHR_R);SPI752_rbuf_1_ip ++;if(SPI752_rbuf_1_ip >= SPI752_RBUF_1_NUMB)SPI752_rbuf_1_ip = 0;}else{rd = SPI752_RegRead(1, SPI752_RHR_R); // 從接受保存寄存器讀空數據 估計是清空該寄存器}}
6.2:應用程序讀取數據
/* 當程序讀取數據時,從緩沖區里取數據 spi_uart.c *//* arg1:SSPI0或SSPI1 arg2:執行可寫的1字節的空間的指針*/
uint8_t SPI752_GetChar(uint8_t Channel, uint8_t *Ch){/* 此處為0通道的讀取數據的代碼 未貼出*/
// SPI752_rbuf_1_ip 是在中斷里面記錄的讀取的字節數if(SPI752_rbuf_1_op != SPI752_rbuf_1_ip){*Ch = SPI752_rbuf_1[SPI752_rbuf_1_op];SPI752_rbuf_1_op ++;if(SPI752_rbuf_1_op >= SPI752_RBUF_1_NUMB)SPI752_rbuf_1_op = 0;return 1;}return 0;}