After writing "Zigbee Journey (9)" on March 3, the author originally planned to immediately start writing a small experiment on "temperature monitoring system" as a summary of a series of scattered knowledge points before. However, I also realized that although each of the previous small experiments was described in detail, the normative and structural nature of its code could be said to be unbearable. Since it is a summary, we should make progress on the original basis, rather than mechanically piecing together the previous small knowledge points. Therefore, I put my original plan on hold, took time to learn the general techniques of embedded development, and wrote two essaysEmbedded C51 programming specification" and "Hierarchy of embedded project code structure》。 This log is not only a summary of Zigbee's first trip, but also incorporates the author's learning experience in recent days, hoping to be helpful to Zigbee beginners.
The full text is organized according to the basic process of software development: requirements analysis, outline design, detailed design, coding implementation, and testing.
1. Demand analysisAfter discussion between the "customer" and the "developer", the following system function description was determined:
… The current room temperature is collected by CC2430-based nodes, and its temperature values can be monitored through a PC
… The CC2430 node itself must have a certain degree of stability and can automatically return to the normal state
… The sampling interval and power management of the node can be controlled by a PC
2. Outline designAccording to the above requirements analysis, we can divide the system into two modules:CC2430 nodeandPC。
[CC2430 Node]
… External parameters can be collected regularly and sent to the PC
… Automatic reset when the machine is turned off
… Commands from the PC can be received and processed accordingly: change the sample interval/power management
[PC]
… The C machine receives and displays data through the serial port tool
… Instructions can be sent to the microcontroller through the serial port tool to control its sampling speed and power management
3. Detailed design(1) Code structure
The layering of the code structure of this system has actually been described in the essay "Hierarchy of embedded project code structure", and the copy is as follows:
(1) Hardware abstraction layer
[ioCC2430.h] (System Included):All SFR and interrupt vectors of the CC2430 are defined
[hal.h] Includes common type definitions, common assignment macros, and common configuration of CC2430 on-chip resources (I/O, serial communication, ADC, timer, power management, etc.)
(2) Functional module layer
[module.h] defines on-chip resources (timers, I/O), off-chip expansion modules (LEDs), and declarations of related functions
[module.cImplement the initialization of each module (LED).
(3) Application layer
[main.cRefer to hal.h, ioCC2430.h, and module.h to achieve specific application requirements such as temperature acquisition, intercommunication with PC, and shutdown and reset
(2) Implementation methods of each module
According to the modules divided according to the outline design, the intrinsic system can be divided into two main modules:CC2430 nodeandPC。
Since there are serial port communication tools on the PC, its functions can meet the requirements, so we do not need to do this part of the PC, and there is no need to analyze it. Let's talk about section CC2430 below
The implementation method of each sub-function of the point:
… Use the timer's count overflow interrupt to trigger timed sampling
… The UART0 mode with serial port transmits temperature data to a PC
… The CC2430's built-in watchdog circuit is used to realize the automatic reset function of the system
… The serial port is used to receive interrupts to capture and respond to control commands from the PC
1) If received@The character is the sampling interval control command, followed by a number indicating the sampling interval: 0-0.5s, 1-1s, 2-2s
如:@0,表示每隔0.5秒采样一次。
2) If received$ The character is the sleep control command, followed by a number indicating the power mode
For example: $3, which means to put the system into power mode 3.
(3) Program flow chart
- Master program flow chart
- Timer 1 Overflow Interrupt Program Flow Chart
- Flow chart of serial port receiving interrupt procedure
4. Coding implementation(1) Hardware abstraction layer
The hardware abstraction layer includes ioCC2430.h and hal.h. Since the former system comes with it, it will not be listed.
The following is a list of all the contents of hal.h (because this file is too long and looks inconvenient, I will show it in modules):
- head
- I/O ports
- Interrupted
- Serial port
- Power and clock management
- Timer
- Watch dog
- ADC
[url=]
[/url]
/***********************************************************
*File name: hal.h
*Author: hustlzp
*Date: March 8, 2011
*Edition: 1.1
*Function description: Hardware abstraction layer
*Modified records:
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Common type definitions
***********************************************************/
typedef unsignedchar BYTE;
typedef unsignedint WORD;
typedef unsignedlong DWORD;
/***********************************************************
Commonly used macro definitions
***********************************************************/
//8 places higher
#defineHIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))
//8 places lower
#defineLOW_BYTE(a) ((BYTE) ((WORD)(a)))
//Assignment
#defineSET_WORD(regH,regL,word)
do{
(regH)=HIGH_BYTE(word);
(regL)=LOW_BYTE(word);
}while(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
I/O ports
***********************************************************/
/*Configure the I/O port direction
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(port, pin, dir)
do{
if(dir == IO_OUT)
P##port##DIR |= (0x01<<(pin));
else
P##port##DIR &= ~(0x01<<(pin));
}while(0)
//The value of the parameter dir is:
#defineIO_IN 0
#defineIO_OUT 1
/*Configure the input mode of the I/O port
-----------------------------------------*/
#defineIO_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)
The value of the parameter PUD is:
#define IO_PULLUP 0 // Pull up
#define IO_PULLDOWN 1 // Pull down
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(port, pin, func)
do {
if((port == 2) && (pin == 3)){
if (func) {
P2SEL |= 0x02;
} else {
P2SEL &= ~0x02;
}
}
else if((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)
The value of the parameter func is:
#define IO_FUNC_GIO 0 // General I/O
#define IO_FUNC_PERIPH 1 // Peripheral I/O
Configure the location of the peripheral 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)
//The value of the parameter imode is:
#defineIO_IMODE_PUD 0 //Pull up/pull down
#defineIO_IMODE_TRI 1 //Three states[url=] [/url]
[url=] [/url]
/***********************************************************
Interrupted
***********************************************************/
//For on/off interrupts
#defineINT_ON 1
#defineINT_OFF 0
//Used to place/clear interrupt flags
#defineINT_SET 1
#defineINT_CLR 0
//Global interrupt settings
#defineINT_GLOBAL_ENABLE(on) EA=(!! on)
//Define the break
#defineINUM_RFERR 0
#defineINUM_ADC 1
#defineINUM_URX0 2
#defineINUM_URX1 3
#defineINUM_ENC 4
#defineINUM_ST 5
#defineINUM_P2INT 6
#defineINUM_UTX0 7
#defineINUM_DMA 8
#defineINUM_T1 9
#defineINUM_T2 10
#defineINUM_T3 11
#defineINUM_T4 12
#defineINUM_P0INT 13
#defineINUM_UTX1 14
#defineINUM_P1INT 15
#defineINUM_RF 16
#defineINUM_WDT 17
/*Interruptions allowed
-----------------------------------------*/
#defineINT_ENABLE(inum, on)
do{
if (inum==INUM_RFERR) { RFERRIE = on; }
else if(inum==INUM_ADC) { ADCIE = on; }
else if(inum==INUM_URX0) { URX0IE = on; }
else if(inum==INUM_URX1) { URX1IE = on; }
else if(inum==INUM_ENC) { ENCIE = on; }
else if(inum==INUM_ST) { STIE = on; }
else if(inum==INUM_P2INT) { (on) ? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
else if(inum==INUM_UTX0) { (on) ? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
else if(inum==INUM_DMA) { DMAIE = on; }
else if(inum==INUM_T1) { T1IE = on; }
else if(inum==INUM_T2) { T2IE = on; }
else if(inum==INUM_T3) { T3IE = on; }
else if(inum==INUM_T4) { T4IE = on; }
else if(inum==INUM_P0INT) { P0IE = on; }
else if(inum==INUM_UTX1) { (on) ? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
else if(inum==INUM_P1INT) { (on) ? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
else if(inum==INUM_RF) { (on) ? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
else if(inum==INUM_WDT) { (on) ? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}while (0)
/*Set the outage priority
-----------------------------------------*/
#defineINT_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)
//The value of the parameter pri is: 0/1/2/3 (highest priority)
//The value of the parameter group is:
#defineRFERR_RF_DMA 0x01//Group IP0
#defineADC_P2INT_T1 0x02//Group IP1
#defineURX0_UTX0_T2 0x04//Group IP2
#defineURX1_UTX1_T3 0x08//Group IP3
#defineENC_P1INT_T4 0x10//Group IP4
#defineST_WDT_P0INT 0x20//Group IP5
/*Get the interrupt flag
-----------------------------------------*/
#defineINT_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
)
/*Set the interrupt flag
-----------------------------------------*/
#defineINT_SETFLAG(inum, f)
do{
if (inum==INUM_RFERR) { RFERRIF= f; }
else if(inum==INUM_ADC) { ADCIF = f; }
else if(inum==INUM_URX0) { URX0IF = f; }
else if(inum==INUM_URX1) { URX1IF = f; }
else if(inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; }
else if(inum==INUM_ST) { STIF = f; }
else if(inum==INUM_P2INT) { P2IF = f; }
else if(inum==INUM_UTX0) { UTX0IF= f; }
else if(inum==INUM_DMA) { DMAIF = f; }
else if(inum==INUM_T1) { T1IF = f; }
else if(inum==INUM_T2) { T2IF = f; }
else if(inum==INUM_T3) { T3IF = f; }
else if(inum==INUM_T4) { T4IF = f; }
else if(inum==INUM_P0INT) { P0IF = f; }
else if(inum==INUM_UTX1) { UTX1IF= f; }
else if(inum==INUM_P1INT) { P1IF = f; }
else if(inum==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
else if(inum==INUM_WDT) { WDTIF = f; }
}while (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Serial port
***********************************************************/
//The value of the BAUD_E corresponding to different baud rates
#defineBAUD_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 )
//The value of the BAUD_M corresponding to different baud rates
#defineBAUD_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)
/*Serial port configuration in UART mode
-----------------------------------------*/
#defineUART_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)
//The value of the parameter receiveEnable:
#defineUART_RECEIVE_ENABLE 0x40 //Receiving permission
#defineUART_RECEIVE_DISABLE 0x00
//The value of the parameter options:
#defineFLOW_CONTROL_ENABLE 0x40 //Flow control
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Occasional verification
#defineODD_PARITY 0x00 //Strange verification
#defineNINE_BIT_TRANSFER 0x10 //9-byte transfer
#defineEIGHT_BIT_TRANSFER 0x00 //8-byte transfer
#definePARITY_ENABLE 0x08 //Parity check enablement
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //2-position stop position
#defineONE_STOP_BITS 0x00 //1 stop position
#defineHIGH_STOP 0x02 //The stop level is high
#defineLOW_STOP 0x00 //The stop position is low
#defineHIGH_START 0x01 //The starting bit level is high
#defineLOW_START 0x00 //The starting bit level is low
//Serial port sends characters
#defineUART_SEND(uart,data)
do{
while(U##uart##CSR &0x01);
U##uart##DBUF = data;
}while (0)
#defineUART0_SEND(data) UART_SEND(0,data)
#defineUART1_SEND(data) UART_SEND(1,data)
//Serial port receives characters
#defineUART_RECEIVE(uart,data)
do{
while(! (U##uart##CSR&0x04));
data=U##uart##DBUF;
}while(0)
#defineUART0_RECEIVE(data) UART_RECEIVE(0,data)
#defineUART1_RECEIVE(data) UART_RECEIVE(1,data)
[url=] [/url]
[url=] [/url]
/***********************************************************
Power and clock management
***********************************************************/
//Get the clock crossover
#defineCLKSPD (CLKCON & 0x07)
//Set the power mode
#defineSET_POWER_MODE(mode)
do{
if(mode ==0) { SLEEP &= ~0x03; }
else if(mode ==3) { SLEEP |=0x03; }
else{ SLEEP &= ~0x03; SLEEP |= mode; }
PCON |=0x01;
asm("NOP");
}while (0)
//The parameter mode is set to the following values:
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Used to detect the stability of high-frequency RC oscillators
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SLEEP & 0x20)
//Used to detect the stable condition of the crystal oscillator
#defineXOSC_STABLE (SLEEP & 0x40)
//Get the tick frequency value of the timer
#defineTICKSPD ((CLKCON & 0x38) >> 3)
//Set the master clock frequency
#defineSET_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)
//The value of the parameter source is:
#defineCRYSTAL 0x00 //Crystal oscillator
#defineRC 0x01 //RC oscillator
[url=] [/url]
[url=] [/url]
/***********************************************************
Timer 1
***********************************************************/
//Timer 1 allows the count overflow to interrupt
#defineTIMER1_ENABLE_OVERFLOW_INT(val)
(TIMIF = (val) ? TIMIF |0x40: TIMIF & ~0x40)
//Set the overflow interrupt flag for timer 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Timer 1 starts
#defineTIMER1_RUN(value) (T1CTL = (value) ? T1CTL|0x02 : T1CTL&~0x03)
//Set the clock division for the timer
#defineSET_TIMER_TICK(value) do{ CLKCON = ((CLKCON & (~0x38)) | value); } while(0)
//The value of value is:
#defineTIMER1_TICK_32M 0x00 //32MHz
#defineTIMER1_TICK_16M 0x08 //16MHz, the default value for system reset
#defineTIMER1_TICK_8M 0x10 //8MHz
#defineTIMER1_TICK_4M 0x18 //4MHz
#defineTIMER1_TICK_2M 0x20 //2MHz
#defineTIMER1_TICK_1M 0x28 //1MHz
#defineTIMER1_TICK_500k 0x30 //500kHz
#defineTIMER1_TICK_250k 0x38 //250kHz
//Set the TICK crossover for timer 1
#defineSET_TIMER1_TICKDIV(value)
do{
T1CTL &= ~0x0c;
T1CTL |= value;
}while (0)
//where the value is:
#defineTIMER1_TICKDIV_1 0x00 //1 division
#defineTIMER1_TICKDIV_8 0x04 //8-way frequency
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Set the timer overflow period
#defineSET_TIMER1_PERIOD(value)
do{
T1CC0H = HIGH_BYTE(value);
T1CC0L = LOW_BYTE(value);
}while (0)
//Set the operating mode of Timer 1
#defineSET_TIMER1_MODE(mode)
do{
T1CTL = ((T1CTL & (~0x03)) | mode);
}while (0)
//The value of mode is:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Watch dog
***********************************************************/
//Set the overflow period for the watchdog timer
#defineWDT_SET_TIMEOUT_PERIOD(timeout)
do{ WDCTL &= ~0x03; WDCTL |= timeout; }while (0)
//The value of the parameter timeout is:
#defineSEC_1 0x00 //after 1 second
#defineM_SEC_250 0x01 //after 250 ms
#defineM_SEC_15 0x02 //after 15 ms
#defineM_SEC_2 0x03 //after 2 ms
//Dog feeding procedures
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} while (0)
//Start/stop the watchdog timer
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Configure a single ADC
#defineADC_SINGLE_CONVERSION(settings)
do{ ADCCON3 = settings; }while(0)
//The parameter setting is composed of the following combinations:
//Reference voltage
#defineADC_REF_1_25_V 0x00 //Internal 1.25V Reference Voltage
#defineADC_REF_P0_7 0x40 //External reference voltage on the AIN7 pin
#defineADC_REF_AVDD 0x80 //AVDD_SOC Pins
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 External reference voltage for differential inputs
//Sampling rate
#defineADC_8_BIT 0x00 //8th place
#defineADC_10_BIT 0x10 //10th place
#defineADC_12_BIT 0x20 //12th place
#defineADC_14_BIT 0x30 //14th place
//Enter the channel
#defineADC_AIN0 0x00 //P0_0
#defineADC_AIN1 0x01 //P0_1
#defineADC_AIN2 0x02 //P0_2
#defineADC_AIN3 0x03 //P0_3
#defineADC_AIN4 0x04 //P0_4
#defineADC_AIN5 0x05 //P0_5
#defineADC_AIN6 0x06 //P0_6
#defineADC_AIN7 0x07 //P0_7
#defineADC_GND 0x0C //Land
#defineADC_TEMP_SENS 0x0E //In-chip temperature sensor
#defineADC_VDD_3 0x0F //vdd/3
ADC conversion is complete
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40; } while (0)//Select the trigger mode of the ADC as manual (i.e., ADC_SAMPLE_READY)
#defineADC_STOP()
do{ ADCCON1 |=0x30; }while (0)[url=] [/url]
(2) Functional module layer
[url=] [/url]
/***********************************************************
*File name: module.h
*Author: hustlzp
*Date: March 6, 2011
*Version: 1.0
*Function description: Functional module layer header file
*Function list: 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);
*Modified records:
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Define the LED pins
#defineled1 P1_0
#defineled2 P1_1
#defineled3 P1_2
#defineled4 P1_3
//LED light and off
#defineLED_OFF 1
#defineLED_ON 0
//LED initialization
voidled_init(void);
/***********************************************************
timer1
***********************************************************/
//Used to set the overflow period value for the timer
#defineTIMER1_OVF_2SEC 0xF424 //2s
#defineTIMER1_OVF_1SEC 0x7A12 //1s
#defineTIMER1_OVF_dot5SEC 0x3D09 //0.5s
//Timer 1 initializes
void timer1_init(void);
/***********************************************************
UART0
***********************************************************/
//UART0 initialization
void uart0_init(void);
//Serial port transmission string
void Uart0SendString(unsignedchar*s);
/***********************************************************
ADC-14
***********************************************************/
//Used to convert the data obtained by the ADC to Celsius temperature
#defineADC_TO_CELSIUS(temp) (temp * 0.06229 - 311.43)
//Initiate ADC conversion
floatadc_start(void);
//Conversion
void get_temperature(unsignedchar*output,floattemp);
/***********************************************************
WatchDog
***********************************************************/
//Watch dog initialization
void watchdog_init(void);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*File name: module.c
*Author: hustlzp
*Date: 2011/3/11
*Version: 1.0
*Function Description: Functional module layer source file
*Function list: (omitted)
*Modified records:
***********************************************************/
#include"module.h"
/***********************************************************
*Function Name: led_init
*Function function: LED initialization
*Entrance parameters: None
*Export parameters: None
***********************************************************/
voidled_init(void)
{
//Configure P1.0, P1.1, P1.2, and P1.3 as general I/O ports
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);
//Configure P1.0, P1.1, P1.2, and P1.3 as outputs
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;
}
/***********************************************************
*Function Name: timer1_init
* Function function: Timer 1 initialization
*Entrance parameters: None
*Export parameters: None
***********************************************************/
voidtimer1_init(void)
{
INT_GLOBAL_ENABLE(INT_ON); //Open the global interruption
INT_ENABLE(INUM_T1, INT_ON); //Open T1 interrupt
TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //Open T1 count overflow interrupt
SET_TIMER_TICK(TIMER1_TICK_4M); //Set the timer TICK to 4MHz
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //Set the counting period for T1 to 2s
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //Set the clock crossover for T1 to 128
SET_TIMER1_MODE(TIMER1_MODE_MODULE); //Set the running mode of T1 to module
}
/***********************************************************
*Function Name: uart0_init
*Function function: Serial port UART0 initialization
*Entrance parameters: None
*Export parameters: None
***********************************************************/
voiduart0_init(void)
{
//Select the UART location
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//Configure UART: Receive allowed, 115200bps, one-bit stop bit, no parity
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);
//Open the total interruption
INT_GLOBAL_ENABLE(INT_ON);
//Open serial port 0 to receive interrupts
INT_ENABLE(INUM_URX0, INT_ON);
}
/***********************************************************
*Function name: Uart0SendString
* Function function: Timer 1 initialization
*Entry parameter: unsigned char *s
The string you want to send
*Export parameters: None
***********************************************************/
voidUart0SendString(unsignedchar*s)
{
while(*s !=0)
UART0_SEND(*s++);
}
/***********************************************************
*Function Name: adc_start
*Function function: Start ADC conversion
*Entrance parameters: None
*Export parameter: float
The temperature value in the tablet
***********************************************************/
floatadc_start(void)
{
unsignedinttemp;
//The reference voltage is 1.25V, the sampling accuracy is 14 bits, and the conversion target is the on-chip temperature sensor
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
ADC_STOP(); //Set the trigger method for ADC conversion to manual
ADC_START(); //Initiate ADC conversion
while(! ADC_SAMPLE_READY()); //Wait for the conversion to complete
temp = ADCL >>2; //Save the conversion results in temp
temp |= (((unsignedint) ADCH) <<6);
returnADC_TO_CELSIUS(temp); //Returns the actual temperature value after conversion
}
/***********************************************************
*Function name: get_temperature
*Function function: Process the temperature value and store it in the character array for serial output
*Entry parameter: unsigned char *output
Used to store the converted temperature value
float temp
Celsius temperature value
*Export parameters: None
***********************************************************/
voidget_temperature(unsignedchar*output,floattemp)
{
output[0] = (unsignedchar)(temp) /10 + 48; //Ten places
output[1] = (unsignedchar)(temp) %10 + 48; //single digit
output[2] ='.'; //Decimal point
output[3] = (unsignedchar)(temp*10) %10 + 48; //Tenth
output[4] = (unsignedchar)(temp*100) %10 + 48; //Percentile
output[5] =''; //String endifiers
}
/***********************************************************
*Function Name: watchdog_init
*Function function: Watch dog initialization
*Entrance parameters: None
*Export parameters: None
***********************************************************/
voidwatchdog_init(void)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1); //Set the timeout time to 1s
WDT_ENABLE(); //Start the watchdog
}
[url=] [/url]
(3) Application layer
[url=] [/url]
/*******************************************************************
File name: main.c
Author: hustlzp
Date: 2011/3/11
Version: 1.0
Function description: Master program file
Function List: (omitted)
Modification Record:
*******************************************************************/
#include
/********************************************************************
Interrupt service procedures
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma vector=T1_VECTOR
__interrupt void T1_ISR(void)
{
EA=0; The gate is interrupted
led2 = LED_ON;
get_temperature(output,adc_start()); Convert the temperature value to an array of characters to be output
Uart0SendString(output); Output temperature value
Uart0SendString("℃");
led2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma vector=URX0_VECTOR
__interrupt void RE_ISR(void)
{
EA=0;
led3 = LED_ON;
receive = U0DBUF;
if(type==1) // type=1, which indicates that the received character is used to set the timer overflow period
{
type=0;
switch(receive)
{
case '0': // Timer overflow period is 0.5s
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
break;
}
case '1': // Timer overflow period is 1s
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
break;
}
case '2': // Timer overflow period is 2s
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
break;
}
}
}
else if(type==2) // type=2, indicating that the received characters are used for sleep control
{
type=0;
led1 = LED_OFF;
led2 = LED_OFF;
led3 = LED_OFF;
switch(receive)
{
case '1': // Enter power mode PM1
{
SET_POWER_MODE(1);
break;
}
case '2': // Enter power mode PM2
{
SET_POWER_MODE(2);
break;
}
case '3': //Enter power mode PM3
{
SET_POWER_MODE(3);
break;
}
}
}
else if(type==0) // type=0, which indicates that the received character is the type of control command: @ or $
{
if(receive=='@')
{
type=1; '@' is received to indicate that the next character is used to set the overflow period
}
else if(receive=='$')
{
type=2; '$' is received, indicating that the next character is used for system sleep control
}
}
led3 = LED_OFF;
EA=1;
}
=LED_OFF;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR); Clear the interruption sign
EA=1; Open interruption
}
/* 主函数
-------------------------------------------------------*/
void main(void)
{
SET_MAIN_CLOCK_SOURCE(CRYSTAL); Set the system clock to 32MHz crystal oscillator
led_init(); LED initialization
uart0_init(); Serial port UART0 initialization
timer1_init(); Timer 1 initializes
watchdog_init(); Watch dog initialization
while(1)
{
WDT_RESET(); Feed the dog constantly
}
}/********************************************************************
Main program
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
unsigned char output[6]={0}; Temperature data is stored for easy serial output
unsigned char receive; Store the received characters
unsigned char type=0; The type flag of the received character is set to 0/1/2"module.h"[url=] [/url]
5. TestingOh~ The code is finally pasted, it's really exhausting, let's test this small system:
(1) Timed sampling
Open the serial port, and start IAR debugging, and find that led1 is on, and the temperature value on the serial port tool is constantly generated, and the sampling interval is determined to be 2s:
(2) Sampling interval control
Enter "@1" in the serial port tool, and then test the sampling interval, and find that it has become 1s; Enter "@0" and the sampling interval has changed to 0.5s.
(3) Sleep control
Enter "$1" in the serial port tool and find that all the LEDs are off and the temperature sampling has stopped:
After testing, the system works normally and stably, and basically meets the requirements.
Students who need source codeClick here to download
6. ConclusionThis paper takes a slightly comprehensive experiment as an example to show how to integrate CC2430 on-chip resources to write a relatively standardized small system. In a few days, I'll take the time to write a simple user manual for hal.h so that I and everyone can easily operate the CC2430.
Next, I will finish my research on CC2430 on-chip resources and devote myself to learning the TI Z-Stack protocol stack~
The blog post writing in this series has come to an end for now, but Zigbee's journey will continue. The scenery ahead is unknown, but I believe that the author will overcome obstacles with everyone and taste the ups and downs, and there will be gains.
Stay tuned: "Join TI Z-Stack" blog posts!