在3月3日寫完“zigbee之旅(九)”后,,筆者本打算立即著手“溫度監(jiān)測系統(tǒng)”小實驗的編寫,,以作為對之前一系列零散知識點的總結(jié)。然而我又意識到,,前面的幾個小實驗雖然每一篇都講得較為詳細,,但是其代碼的規(guī)范性、結(jié)構(gòu)性,,可以說是不堪入目的,。既然是小結(jié),就應(yīng)當在原來的基礎(chǔ)上有所進步,,而不是機械地把前面的小知識點拼湊起來了事,。因此,我暫停了原來的計劃,,抽出時間去學習了一下嵌入式開發(fā)的通用技巧,,寫下了兩篇隨筆《嵌入式C51編程規(guī)范》和《嵌入式項目代碼結(jié)構(gòu)的分層》。本篇日志,,既是Zigbee首次旅行的一個階段性小結(jié),,也融入了筆者近幾天的學習心得,希望能對Zigbee初學者有所幫助,。 全文按軟件開發(fā)的基本流程來組織:需求分析,、概要設(shè)計、詳細設(shè)計、編碼實現(xiàn),、測試,。 一、需求分析經(jīng)“客戶”與“開發(fā)者”共同商討,,確定了如下的系統(tǒng)功能描述: 使用基于CC2430的節(jié)點采集當前室溫,,并可通過PC監(jiān)測其溫度數(shù)值 CC2430節(jié)點本身需具備一定的穩(wěn)定性,可自動恢復正常狀態(tài) 可通過PC來控制節(jié)點的采樣間隔與電源管理 二,、概要設(shè)計根據(jù)上述需求分析,,我們可以把系統(tǒng)分為兩大模塊:CC2430節(jié)點 與 PC機。 [CC2430節(jié)點] 可定時采集外部參數(shù),,并發(fā)送至PC端 停機時自動復位 可接收來自PC機的指令,,并作出相應(yīng)處理:改變采樣間隔/電源管理 [PC機] PC機通過串口工具接收數(shù)據(jù)并顯示 可通過串口工具向單片機發(fā)送指令,控制其采樣速度,,電源管理 三,、詳細設(shè)計(1)代碼結(jié)構(gòu) 本系統(tǒng)代碼結(jié)構(gòu)的分層,其實已在隨筆《嵌入式項目代碼結(jié)構(gòu)的分層》中提到了,,現(xiàn)copy如下: ?。?)硬件抽象層 [ioCC2430.h](系統(tǒng)自帶):定義了CC2430的所有SFR ,、中斷向量 [hal.h] 包括常用類型定義,、常用賦值宏、以及CC2430片上資源的通用配置(I/O,、串口通訊,、ADC、定時器,、電源管理等) (2)功能模塊層 [module.h] 定義了片內(nèi)資源(定時器,、I/O)片外擴展模塊(LED),以及相關(guān)函數(shù)的聲明 [module.c] 實現(xiàn)各模塊(LED)的初始化 (3)應(yīng)用程序?qū)?/STRONG> [main.c] 引用 hal.h,、ioCC2430.h 與 module.h,,實現(xiàn)溫度采集、與PC互通信,、停機復位等具體的應(yīng)用需求 (2)各模塊實現(xiàn)方法 根據(jù)概要設(shè)計中所劃分的模塊包括,,本性系統(tǒng)可分為兩大模塊:CC2430節(jié)點 和 PC機。 由于PC機上已有串口通信工具,,其功能已能滿足要求,,所以PC這一部分我們不需要做,沒必要對其分析,。下面談一下CC2430節(jié) 利用定時器的計數(shù)溢出中斷,,來觸發(fā)定時采樣 使用串口的 UART0 模式將溫度數(shù)據(jù)傳送至PC 利用CC2430自帶的看門狗電路,實現(xiàn)系統(tǒng)的停機自動復位功能 利用串口接收中斷,,來實現(xiàn)對來自PC端的控制指令的捕獲與響應(yīng) 1) 若接收到 @ 字符,,則為采樣間隔控制命令,,后面緊跟的一個數(shù)字表示采樣間隔:0——0.5s、1——1s,、2——2s (3)程序流程圖 四,、編碼實現(xiàn)(1)硬件抽象層 硬件抽象層包括 ioCC2430.h 和 hal.h。由于前者系統(tǒng)自帶,,就不列出來了,。 下面把 hal.h 的全部內(nèi)容列出來(由于這個文件太長,看起來不方便,,我就分模塊展示): /***********************************************************
*文件名稱: hal.h *作 者: hustlzp *日 期: 2011/3/8 *版 本: 1.1 *功能說明: 硬件抽象層 *修改記錄: ***********************************************************/ #ifndef HAL_H #define HAL_H #include <ioCC2430.h> /*********************************************************** 常用類型定義 ***********************************************************/ typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; /*********************************************************** 常用宏定義 ***********************************************************/ //高8位 #define HIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8)) //低8位 #define LOW_BYTE(a) ((BYTE) ((WORD)(a))) //賦值 #define SET_WORD(regH,regL,word) \ do{ \ (regH)=HIGH_BYTE(word); \ (regL)=LOW_BYTE(word); \ }while(0) /***********************************************************
I/O口 ***********************************************************/ /*配置I/O口方向 -----------------------------------------*/ #define IO_DIR_PORT_PIN(port, pin, dir) \ do { \ if (dir == IO_OUT) \ P##port##DIR |= (0x01<<(pin)); \ else \ P##port##DIR &=~(0x01<<(pin)); \ }while(0) //其中參數(shù) dir 的取值為: #define IO_IN 0 #define IO_OUT 1 /*配置I/O口的輸入模式 -----------------------------------------*/ #define IO_IMODE_PORT_PIN(port, pin, imode) \ do { \ if (imode == IO_IMODE_TRI) \ P##port##INP |= (0x01<<(pin)); \ else \ P##port##INP &=~(0x01<<(pin)); \ } while (0) #define IO_PUD_PORT(port, pud) \ do { \ if (pud == IO_PULLDOWN) \ P2INP |= (0x01<< (port+5)); \ else \ P2INP &=~(0x01<< (port+5));\ } while (0) //其中參數(shù) pud 的取值為: #define IO_PULLUP 0 //上拉 #define IO_PULLDOWN 1 //下拉 /*配置I/O口的功能 -----------------------------------------*/ #define IO_FUNC_PORT_PIN(port, pin, func) \ do { \ if((port ==2) && (pin ==3)){ \ if (func) { \ P2SEL |=0x02; \ } else { \ P2SEL &=~0x02; \ } \ } \ elseif((port ==2) && (pin ==4)){ \ if (func) { \ P2SEL |=0x04; \ } else { \ P2SEL &=~0x04; \ } \ } \ else{ \ if (func) { \ P##port##SEL |= (0x01<<(pin)); \ } else { \ P##port##SEL &=~(0x01<<(pin));\ } \ } \ } while (0) //其中參數(shù) func 的取值為: #define IO_FUNC_GIO 0 // 通用I/O #define IO_FUNC_PERIPH 1 // 外設(shè)I/O // 配置外設(shè)I/O的位置 #define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } while (0) #define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } while (0) #define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } while (0) #define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } while (0) #define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } while (0) #define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } while (0) #define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } while (0) #define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } while (0) #define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } while (0) #define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } while (0) #define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } while (0) #define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } while (0) #define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } while (0) #define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } while (0) //其中參數(shù) imode 的取值為: /***********************************************************
中斷 ***********************************************************/ // 用于開/關(guān)中斷 #define INT_ON 1 #define INT_OFF 0 // 用于置位/清除中斷標志 #define INT_SET 1 #define INT_CLR 0 // 全局中斷設(shè)置 #define INT_GLOBAL_ENABLE(on) EA=(!!on) //定義中斷 #define INUM_RFERR 0 #define INUM_ADC 1 #define INUM_URX0 2 #define INUM_URX1 3 #define INUM_ENC 4 #define INUM_ST 5 #define INUM_P2INT 6 #define INUM_UTX0 7 #define INUM_DMA 8 #define INUM_T1 9 #define INUM_T2 10 #define INUM_T3 11 #define INUM_T4 12 #define INUM_P0INT 13 #define INUM_UTX1 14 #define INUM_P1INT 15 #define INUM_RF 16 #define INUM_WDT 17 /*中斷允許 -----------------------------------------*/ #define INT_ENABLE(inum, on) \ do { \ if (inum==INUM_RFERR) { RFERRIE = on; } \ elseif (inum==INUM_ADC) { ADCIE = on; } \ elseif (inum==INUM_URX0) { URX0IE = on; } \ elseif (inum==INUM_URX1) { URX1IE = on; } \ elseif (inum==INUM_ENC) { ENCIE = on; } \ elseif (inum==INUM_ST) { STIE = on; } \ elseif (inum==INUM_P2INT) { (on) (IEN2 |=0x02) : (IEN2 &=~0x02); } \ elseif (inum==INUM_UTX0) { (on) (IEN2 |=0x04) : (IEN2 &=~0x04); } \ elseif (inum==INUM_DMA) { DMAIE = on; } \ elseif (inum==INUM_T1) { T1IE = on; } \ elseif (inum==INUM_T2) { T2IE = on; } \ elseif (inum==INUM_T3) { T3IE = on; } \ elseif (inum==INUM_T4) { T4IE = on; } \ elseif (inum==INUM_P0INT) { P0IE = on; } \ elseif (inum==INUM_UTX1) { (on) (IEN2 |=0x08) : (IEN2 &=~0x08); } \ elseif (inum==INUM_P1INT) { (on) (IEN2 |=0x10) : (IEN2 &=~0x10); } \ elseif (inum==INUM_RF) { (on) (IEN2 |=0x01) : (IEN2 &=~0x01); } \ elseif (inum==INUM_WDT) { (on) (IEN2 |=0x20) : (IEN2 &=~0x20); } \ } while (0) /*設(shè)置中斷優(yōu)先級 -----------------------------------------*/ #define INT_PRIORITY(group, pri) \ do { \ if (pri ==0) { IP0 &=~group; IP1 &=~group; } \ if (pri ==1) { IP0 |= group; IP1 &=~group; } \ if (pri ==2) { IP0 &=~group; IP1 |= group; } \ if (pri ==3) { IP0 |= group; IP1 |= group; } \ } while (0) // 其中參數(shù) pri 的取值為:0/1/2/3(最高優(yōu)先級) // 其中參數(shù) group 的取值為: #define RFERR_RF_DMA 0x01 // Group IP0 #define ADC_P2INT_T1 0x02 // Group IP1 #define URX0_UTX0_T2 0x04 // Group IP2 #define URX1_UTX1_T3 0x08 // Group IP3 #define ENC_P1INT_T4 0x10 // Group IP4 #define ST_WDT_P0INT 0x20 // Group IP5 /*獲取中斷標志 -----------------------------------------*/ #define INT_GETFLAG(inum) ( \ (inum==INUM_RFERR) RFERRIF : \ (inum==INUM_ADC) ADCIF : \ (inum==INUM_URX0) URX0IF : \ (inum==INUM_URX1) URX1IF : \ (inum==INUM_ENC) ENCIF_0 : \ (inum==INUM_ST) STIF : \ (inum==INUM_P2INT) P2IF : \ (inum==INUM_UTX0) UTX0IF : \ (inum==INUM_DMA) DMAIF : \ (inum==INUM_T1) T1IF : \ (inum==INUM_T2) T2IF : \ (inum==INUM_T3) T3IF : \ (inum==INUM_T4) T4IF : \ (inum==INUM_P0INT) P0IF : \ (inum==INUM_UTX1) UTX1IF : \ (inum==INUM_P1INT) P1IF : \ (inum==INUM_RF) S1CON &=~0x03 : \ (inum==INUM_WDT) WDTIF : \ 0 \ ) /*設(shè)置中斷標志 -----------------------------------------*/ #define INT_SETFLAG(inum, f) \ do { \ if (inum==INUM_RFERR) { RFERRIF= f; } \ elseif (inum==INUM_ADC) { ADCIF = f; } \ elseif (inum==INUM_URX0) { URX0IF = f; } \ elseif (inum==INUM_URX1) { URX1IF = f; } \ elseif (inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; } \ elseif (inum==INUM_ST) { STIF = f; } \ elseif (inum==INUM_P2INT) { P2IF = f; } \ elseif (inum==INUM_UTX0) { UTX0IF= f; } \ elseif (inum==INUM_DMA) { DMAIF = f; } \ elseif (inum==INUM_T1) { T1IF = f; } \ elseif (inum==INUM_T2) { T2IF = f; } \ elseif (inum==INUM_T3) { T3IF = f; } \ elseif (inum==INUM_T4) { T4IF = f; } \ elseif (inum==INUM_P0INT) { P0IF = f; } \ elseif (inum==INUM_UTX1) { UTX1IF= f; } \ elseif (inum==INUM_P1INT) { P1IF = f; } \ elseif (inum==INUM_RF) { (f) (S1CON |=0x03) : (S1CON &=~0x03); } \ elseif (inum==INUM_WDT) { WDTIF = f; } \ } while (0) /***********************************************************
串口 ***********************************************************/ // 不同波特率對應(yīng)的BAUD_E的值 #define BAUD_E(baud, clkDivPow) ( \ (baud==2400) 6+clkDivPow : \ (baud==4800) 7+clkDivPow : \ (baud==9600) 8+clkDivPow : \ (baud==14400) 8+clkDivPow : \ (baud==19200) 9+clkDivPow : \ (baud==28800) 9+clkDivPow : \ (baud==38400) 10+clkDivPow : \ (baud==57600) 10+clkDivPow : \ (baud==76800) 11+clkDivPow : \ (baud==115200) 11+clkDivPow : \ (baud==153600) 12+clkDivPow : \ (baud==230400) 12+clkDivPow : \ (baud==307200) 13+clkDivPow : \ 0 ) // 不同波特率對應(yīng)的BAUD_M的值 #define BAUD_M(baud) ( \ (baud==2400) 59 : \ (baud==4800) 59 : \ (baud==9600) 59 : \ (baud==14400) 216 : \ (baud==19200) 59 : \ (baud==28800) 216 : \ (baud==38400) 59 : \ (baud==57600) 216 : \ (baud==76800) 59 : \ (baud==115200) 216 : \ (baud==153600) 59 : \ (baud==230400) 216 : \ (baud==307200) 59 : \ 0) /* UART模式下的串口配置 -----------------------------------------*/ #define UART_SETUP(uart, receiveEnable, baudRate, options) \ do { \ if((uart) ==0){ \ if(PERCFG &0x01){ \ P1SEL |=0x30; \ } else { \ P0SEL |=0x0C; \ } \ } \ else { \ if(PERCFG &0x02){ \ P1SEL |=0xC0; \ } else { \ P0SEL |=0x30; \ } \ } \ \ U##uart##GCR = BAUD_E((baudRate),CLKSPD); \ U##uart##BAUD = BAUD_M(baudRate); \ \ U##uart##CSR |=0x80; \ \ U##uart##CSR |= receiveEnable; \ \ U##uart##UCR |= ((options) |0x80); \ } while(0) //其中參數(shù) receiveEnable 的取值: #define UART_RECEIVE_ENABLE 0x40 //接收允許 #define UART_RECEIVE_DISABLE 0x00 // 其中參數(shù) options 的取值: #define FLOW_CONTROL_ENABLE 0x40 //流控制 #define FLOW_CONTROL_DISABLE 0x00 #define EVEN_PARITY 0x20 //偶校驗 #define ODD_PARITY 0x00 //奇校驗 #define NINE_BIT_TRANSFER 0x10 //9字節(jié)傳輸 #define EIGHT_BIT_TRANSFER 0x00 //8字節(jié)傳輸 #define PARITY_ENABLE 0x08 //奇偶校驗使能 #define PARITY_DISABLE 0x00 #define TWO_STOP_BITS 0x04 //2位停止位 #define ONE_STOP_BITS 0x00 //1位停止位 #define HIGH_STOP 0x02 //停止位高電平 #define LOW_STOP 0x00 //停止位低電平 #define HIGH_START 0x01 //起始位電平高 #define LOW_START 0x00 //起始位電平低 //串口發(fā)送字符 #define UART_SEND(uart,data) \ do{ \ while(U##uart##CSR &0x01); \ U##uart##DBUF = data; \ } while (0) #define UART0_SEND(data) UART_SEND(0,data) #define UART1_SEND(data) UART_SEND(1,data) //串口接收字符 #define UART_RECEIVE(uart,data) \ do{ \ while(!(U##uart##CSR&0x04)); \ data=U##uart##DBUF; \ } while(0) #define UART0_RECEIVE(data) UART_RECEIVE(0,data) #define UART1_RECEIVE(data) UART_RECEIVE(1,data) /***********************************************************
電源及時鐘管理 ***********************************************************/ // 獲取時鐘分頻 #define CLKSPD (CLKCON & 0x07) // 設(shè)置電源模式 #define SET_POWER_MODE(mode) \ do { \ if(mode ==0) { SLEEP &=~0x03; } \ elseif (mode ==3) { SLEEP |=0x03; } \ else { SLEEP &=~0x03; SLEEP |= mode; } \ PCON |=0x01; \ asm("NOP"); \ }while (0) // 參數(shù) mode 的取值為: #define POWER_MODE_0 0x00 #define POWER_MODE_1 0x01 #define POWER_MODE_2 0x02 #define POWER_MODE_3 0x03 // 用于檢測高頻RC振蕩器的穩(wěn)定狀況 #define HIGH_FREQUENCY_RC_OSC_STABLE (SLEEP & 0x20) // 用于檢測晶體振蕩器的穩(wěn)定狀況 #define XOSC_STABLE (SLEEP & 0x40) // 獲取定時器的tick頻率值 #define TICKSPD ((CLKCON & 0x38) >> 3) // 設(shè)置主時鐘頻率 #define SET_MAIN_CLOCK_SOURCE(source) \ do { \ if(source) { \ CLKCON |=0x40; \ while(!HIGH_FREQUENCY_RC_OSC_STABLE); \ if(TICKSPD ==0){ \ CLKCON |=0x08; \ } \ SLEEP |=0x04; \ } \ else { \ SLEEP &=~0x04; \ while(!XOSC_STABLE); \ asm("NOP"); \ CLKCON &=~0x47; \ SLEEP |=0x04; \ } \ }while (0) // 其中參數(shù) source 的取值為: #define CRYSTAL 0x00 //晶體振蕩器 #define RC 0x01 //RC振蕩器 /***********************************************************
定時器1 ***********************************************************/ //定時器1允許計數(shù)溢出中斷 #define TIMER1_ENABLE_OVERFLOW_INT(val) \ (TIMIF = (val) TIMIF |0x40 : TIMIF &~0x40) //設(shè)置定時器1的溢出中斷標志 #define TIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f)) //定時器1啟動 #define TIMER1_RUN(value) (T1CTL = (value) ? T1CTL|0x02 : T1CTL&~0x03) //設(shè)置定時器的時鐘分頻 #define SET_TIMER_TICK(value) do{ CLKCON = ((CLKCON & (~0x38)) | value);} while(0) //其中value的取值為: #define TIMER1_TICK_32M 0x00 // 32MHz #define TIMER1_TICK_16M 0x08 // 16MHz,系統(tǒng)復位默認值 #define TIMER1_TICK_8M 0x10 // 8MHz #define TIMER1_TICK_4M 0x18 // 4MHz #define TIMER1_TICK_2M 0x20 // 2MHz #define TIMER1_TICK_1M 0x28 // 1MHz #define TIMER1_TICK_500k 0x30 // 500kHz #define TIMER1_TICK_250k 0x38 // 250kHz //設(shè)置定時器1的TICK分頻 #define SET_TIMER1_TICKDIV(value) \ do{ \ T1CTL &=~0x0c; \ T1CTL |= value; \ } while (0) //其中 value 的取值為: #define TIMER1_TICKDIV_1 0x00 //1分頻 #define TIMER1_TICKDIV_8 0x04 //8分頻 #define TIMER1_TICKDIV_32 0x08 #define TIMER1_TICKDIV_128 0x0c //設(shè)置定時器溢出周期 #define SET_TIMER1_PERIOD(value) \ do{ \ T1CC0H = HIGH_BYTE(value); \ T1CC0L = LOW_BYTE(value); \ } while (0) //設(shè)置定時器1的運行模式 #define SET_TIMER1_MODE(mode) \ do{ \ T1CTL = ((T1CTL & (~0x03)) | mode); \ } while (0) //其中 mode 的取值為: #define TIMER1_MODE_STOP 0x00 #define TIMER1_MODE_FREE 0x01 #define TIMER1_MODE_MODULE 0x02 #define TIMER1_MODE_UPDOWN 0x03 /***********************************************************
看門狗 ***********************************************************/ // 設(shè)置看門狗定時器的溢出周期 #define WDT_SET_TIMEOUT_PERIOD(timeout) \ do { WDCTL &=~0x03; WDCTL |= timeout; } while (0) // 其中參數(shù) timeout 的取值為: #define SEC_1 0x00 // after 1 second #define M_SEC_250 0x01 // after 250 ms #define M_SEC_15 0x02 // after 15 ms #define M_SEC_2 0x03 // after 2 ms // 喂狗程序 #define WDT_RESET() do { \ WDCTL = (WDCTL &~0xF0) |0xA0; \ WDCTL = (WDCTL &~0xF0) |0x50; \ } while (0) // 啟動/停止看門狗定時器 #define WDT_ENABLE() WDCTL |= 0x08 #define WDT_DISABLE() WDCTL &= ~0x08 /***********************************************************
ADC ***********************************************************/ // 配置單次ADC #define ADC_SINGLE_CONVERSION(settings) \ do{ ADCCON3 = settings; }while(0) // 其中的參數(shù) setting 由下面的組合構(gòu)成 // 參考電壓 #define ADC_REF_1_25_V 0x00 // 內(nèi)部 1.25V 參考電壓 #define ADC_REF_P0_7 0x40 // AIN7 引腳上的外部參考電壓 #define ADC_REF_AVDD 0x80 // AVDD_SOC 引腳 #define ADC_REF_P0_6_P0_7 0xC0 // AIN6-AIN7 差分輸入的外部參考電壓 // 采樣速率 #define ADC_8_BIT 0x00 // 8位 #define ADC_10_BIT 0x10 // 10位 #define ADC_12_BIT 0x20 // 12位 #define ADC_14_BIT 0x30 // 14位 // 輸入頻道 #define ADC_AIN0 0x00 // P0_0 #define ADC_AIN1 0x01 // P0_1 #define ADC_AIN2 0x02 // P0_2 #define ADC_AIN3 0x03 // P0_3 #define ADC_AIN4 0x04 // P0_4 #define ADC_AIN5 0x05 // P0_5 #define ADC_AIN6 0x06 // P0_6 #define ADC_AIN7 0x07 // P0_7 #define ADC_GND 0x0C // 地 #define ADC_TEMP_SENS 0x0E // 片內(nèi)溫度傳感器 #define ADC_VDD_3 0x0F // vdd/3
// ADC轉(zhuǎn)換完成的標志 #define ADC_SAMPLE_READY() (ADCCON1 & 0x80) #endif //啟動ADC轉(zhuǎn)化 (2)功能模塊層 /***********************************************************
*文件名稱: module.h *作 者: hustlzp *日 期: 2011/3/6 *版 本: 1.0 *功能說明: 功能模塊層頭文件 *函數(shù)列表: void led_init() void timer1_init() void uart0_init(void); void Uart0SendString(unsigned char *s); float adc_start(void) void get_temperature(unsigned char *output,float temp); void watchdog_init(void); *修改記錄: ***********************************************************/ #ifndef MODULE_H #define MODULE_H #include "hal.h" /*********************************************************** LED ***********************************************************/ //定義LED引腳 #define led1 P1_0 #define led2 P1_1 #define led3 P1_2 #define led4 P1_3 //led亮與滅 #define LED_OFF 1 #define LED_ON 0 //LED初始化 void led_init(void); /*********************************************************** timer1 ***********************************************************/ //用于設(shè)置定時器的溢出周期值 #define TIMER1_OVF_2SEC 0xF424 // 2s #define TIMER1_OVF_1SEC 0x7A12 // 1s #define TIMER1_OVF_dot5SEC 0x3D09 // 0.5s //定時器1初始化 void timer1_init(void); /*********************************************************** UART0 ***********************************************************/ //UART0初始化 void uart0_init(void); //串口傳送字符串 void Uart0SendString(unsigned char*s); /*********************************************************** ADC-14 ***********************************************************/ //用于將ADC得到的數(shù)據(jù)轉(zhuǎn)化為攝氏溫度 #define ADC_TO_CELSIUS(temp) (temp * 0.06229 - 311.43) //啟動ADC轉(zhuǎn)換 float adc_start(void); //轉(zhuǎn)換 void get_temperature(unsigned char*output,float temp); /*********************************************************** WatchDog ***********************************************************/ //看門狗初始化 void watchdog_init(void); #endif /***********************************************************
*文件名稱: module.c *作 者: hustlzp *日 期: 2011/3/11 *版 本: 1.0 *功能說明: 功能模塊層源文件 *函數(shù)列表: (略) *修改記錄: ***********************************************************/ #include "module.h" /*********************************************************** *函數(shù)名稱: led_init *函數(shù)功能: LED初始化 *入口參數(shù): 無 *出口參數(shù): 無 ***********************************************************/ void led_init(void) { //配置P1.0 P1.1 P1.2 P1.3 為通用I/O口 IO_FUNC_PORT_PIN(1, 0, IO_FUNC_GIO); IO_FUNC_PORT_PIN(1, 1, IO_FUNC_GIO); IO_FUNC_PORT_PIN(1, 2, IO_FUNC_GIO); IO_FUNC_PORT_PIN(1, 3, IO_FUNC_GIO); //配置P1.0 P1.1 P1.2 P1.3 為輸出 IO_DIR_PORT_PIN(1, 0, IO_OUT); IO_DIR_PORT_PIN(1, 1, IO_OUT); IO_DIR_PORT_PIN(1, 2, IO_OUT); IO_DIR_PORT_PIN(1, 3, IO_OUT); led1 = LED_ON; led2 = LED_OFF; led3 = LED_OFF; led4 = LED_OFF; } /*********************************************************** *函數(shù)名稱: timer1_init *函數(shù)功能: 定時器1初始化 *入口參數(shù): 無 *出口參數(shù): 無 ***********************************************************/ void timer1_init(void) { INT_GLOBAL_ENABLE(INT_ON); //開全局中斷 INT_ENABLE(INUM_T1, INT_ON); //開T1中斷 TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //開T1計數(shù)溢出中斷 SET_TIMER_TICK(TIMER1_TICK_4M); //設(shè)置定時器TICK為4MHz SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //設(shè)置T1的計數(shù)周期為2s SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //設(shè)置T1的時鐘分頻為128 SET_TIMER1_MODE(TIMER1_MODE_MODULE); //設(shè)置T1的運行模式為module } /*********************************************************** *函數(shù)名稱: uart0_init *函數(shù)功能: 串口UART0初始化 *入口參數(shù): 無 *出口參數(shù): 無 ***********************************************************/ void uart0_init(void) { //選擇uart位置 IO_PER_LOC_UART0_AT_PORT0_PIN2345(); //配置uart:接收允許,,115200bps,一位停止位,,無奇偶校驗 UART_SETUP(0, UART_RECEIVE_ENABLE, 115200, ONE_STOP_BITS | PARITY_DISABLE); //開總中斷 INT_GLOBAL_ENABLE(INT_ON); //開串口0接收中斷 INT_ENABLE(INUM_URX0, INT_ON); } /*********************************************************** *函數(shù)名稱: Uart0SendString *函數(shù)功能: 定時器1初始化 *入口參數(shù): unsigned char *s 想要發(fā)送的字符串 *出口參數(shù): 無 ***********************************************************/ void Uart0SendString(unsigned char*s) { while(*s !=0) UART0_SEND(*s++); } /*********************************************************** *函數(shù)名稱: adc_start *函數(shù)功能: 啟動ADC轉(zhuǎn)換 *入口參數(shù): 無 *出口參數(shù): float 片內(nèi)的攝氏溫度值 ***********************************************************/ float adc_start(void) { unsigned int temp; //參考電壓選擇1.25V,,采樣精度為14位,轉(zhuǎn)換目標為片內(nèi)溫度傳感器 ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS); ADC_STOP(); //設(shè)置ADC轉(zhuǎn)化的觸發(fā)方式為手動 ADC_START(); //啟動ADC轉(zhuǎn)化 while(!ADC_SAMPLE_READY()); //等待轉(zhuǎn)化完成 temp = ADCL >>2; //將轉(zhuǎn)化結(jié)果存入temp中 temp |= (((unsigned int) ADCH) <<6); return ADC_TO_CELSIUS(temp); //返回轉(zhuǎn)換后的實際溫度值 } /*********************************************************** *函數(shù)名稱: get_temperature *函數(shù)功能: 將溫度值處理后存入字符數(shù)組中,,便于串口輸出 *入口參數(shù): unsigned char *output 用于存儲轉(zhuǎn)換后的溫度值 float temp 攝氏溫度值 *出口參數(shù): 無 ***********************************************************/ void get_temperature(unsigned char*output,float temp) { output[0] = (unsigned char)(temp) /10+48; //十位 output[1] = (unsigned char)(temp) %10+48; //個位 output[2] ='.'; //小數(shù)點 output[3] = (unsigned char)(temp*10) %10+48; //十分位 output[4] = (unsigned char)(temp*100) %10+48; //百分位 output[5] ='\0'; //字符串結(jié)束符 } /*********************************************************** *函數(shù)名稱: watchdog_init *函數(shù)功能: 看門狗初始化 *入口參數(shù): 無 *出口參數(shù): 無 ***********************************************************/ void watchdog_init(void) { WDT_SET_TIMEOUT_PERIOD(SEC_1); //設(shè)置超時時間為1s WDT_ENABLE(); //啟動看門狗 } (3)應(yīng)用程序?qū)?/SPAN> /*******************************************************************
文件名稱: main.c 作 者: hustlzp 日 期: 2011/3/11 版 本: 1.0 功能說明: 主程序文件 函數(shù)列表: (略) 修改記錄: *******************************************************************/ #include /******************************************************************** 中斷服務(wù)程序 ********************************************************************/ /* 定時器1溢出中斷子程序 -------------------------------------------------------*/ #pragma vector=T1_VECTOR __interrupt void T1_ISR(void) { EA=0; //關(guān)中斷 led2 = LED_ON; get_temperature(output,adc_start()); //將溫度值轉(zhuǎn)換為待輸出的字符數(shù)組 Uart0SendString(output); //輸出溫度值 Uart0SendString("℃\r\n"); led2 /* 串口接收中斷子程序 -------------------------------------------------------*/ #pragma vector=URX0_VECTOR __interrupt void RE_ISR(void) { EA=0; led3 = LED_ON; receive = U0DBUF; if(type==1) // type=1,,表示接收到的字符用于設(shè)置定時器溢出周期 { type=0; switch(receive) { case'0': //定時器溢出周期為0.5s { SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC); break; } case'1': //定時器溢出周期為1s { SET_TIMER1_PERIOD(TIMER1_OVF_1SEC); break; } case'2': //定時器溢出周期為2s { SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); break; } } } elseif(type==2) // type=2,表示接收到的字符用于睡眠控制 { type=0; led1 = LED_OFF; led2 = LED_OFF; led3 = LED_OFF; switch(receive) { case'1': //進入電源模式PM1 { SET_POWER_MODE(1); break; } case'2': //進入電源模式PM2 { SET_POWER_MODE(2); break; } case'3': //進入電源模式PM3 { SET_POWER_MODE(3); break; } } } elseif(type==0) // type=0,,表示接收到的字符為控制命令的種類:@ 或 $ { if(receive=='@') { type=1; //接收到'@',,表示下一個字符用于設(shè)置溢出周期 } elseif(receive=='$') { type=2; //接收到'$',表示下一個字符用于系統(tǒng)睡眠控制 } } led3 = LED_OFF; EA=1; } =LED_OFF; 五,、測試吁~代碼終于貼完了,真是累死了,,下面我們來測試一下這個小系統(tǒng): (1)定時采樣 打開串口,,并啟動IAR調(diào)試,發(fā)現(xiàn) led1 亮,,同時串口工具上不斷有溫度值產(chǎn)生,,采樣間隔經(jīng)測定為2s:
(2)采樣間隔控制 在串口工具中輸入"@1",然后再測試采樣間隔,,發(fā)現(xiàn)已變?yōu)?s,;輸入"@0",采樣間隔已變?yōu)?.5s。 (3)睡眠控制 在串口工具中輸入"$1",,發(fā)現(xiàn) led 全部熄滅,,溫度采樣也已停止: 經(jīng)測試,本系統(tǒng)工作正常穩(wěn)定,,基本符合要求,。 需要源碼的同學點此下載 六、結(jié)語本文以一個稍具綜合性的小實驗為例,,展示了如何整合CC2430片上資源,,編寫出一個比較規(guī)范的小系統(tǒng)。過幾天我會抽時間為 hal.h 編寫一個簡單的使用手冊,,方便自己和大家便捷地操控 CC2430,。 接下來,筆者將會結(jié)束針對 CC2430 片上資源的研究,,全力投入到 TI Z-Stack 協(xié)議棧的學習中~ 本系列的博文寫作暫時結(jié)束了,,但Zigbee的旅行仍將繼續(xù)。前方的風景未知,,但相信筆者和大家一起披荊斬棘,,遍嘗酸甜苦辣,定會有所斬獲,。 敬請期待:"登臨 TI Z-Stack" 系列博文,! |
|