Nachdem er am 3. März "Zigbee Journey (9)" geschrieben hatte, plante der Autor ursprünglich, sofort mit einem kleinen Experiment über das "Temperaturüberwachungssystem" zu beginnen, als Zusammenfassung einer Reihe verstreuter Wissenspunkte. Allerdings wurde mir auch klar, dass, obwohl jedes der vorherigen kleinen Experimente im Detail beschrieben wurde, die normative und strukturelle Natur seines Codes als unerträglich bezeichnet werden konnte. Da es eine Zusammenfassung ist, sollten wir auf der ursprünglichen Basis voranschreiten, anstatt die vorherigen kleinen Wissenspunkte mechanisch zusammenzusetzen. Deshalb habe ich meinen ursprünglichen Plan auf Eis gelegt, mir Zeit genommen, die allgemeinen Techniken der Embedded-Entwicklung zu lernen, und zwei Essays geschriebenProgrammierspezifikation für eingebettete C51" und "Hierarchie der eingebetteten Projektcode-Struktur》。 Dieses Protokoll ist nicht nur eine Zusammenfassung von Zigbees erster Reise, sondern enthält auch die Lernerfahrungen des Autors in den letzten Tagen, in der Hoffnung, Zigbee-Anfängern hilfreich zu sein.
Der Volltext ist nach dem grundlegenden Prozess der Softwareentwicklung organisiert: Anforderungsanalyse, Gliederungsdesign, detailliertes Design, Codierungsimplementierung und Testing.
1. NachfrageanalyseNach Diskussion zwischen dem "Kunden" und dem "Entwickler" wurde folgende Systemfunktionsbeschreibung festgelegt:
… Die aktuelle Raumtemperatur wird von CC2430-basierten Knoten erfasst, und ihre Temperaturwerte können über einen PC überwacht werden
… Der CC2430-Knoten selbst muss ein gewisses Maß an Stabilität aufweisen und kann automatisch in den normalen Zustand zurückkehren
… Das Abtastintervall und die Energieverwaltung des Knotens können von einem PC gesteuert werden
2. GliederungsdesignNach der obigen Anforderungsanalyse können wir das System in zwei Module unterteilen:CC2430-KnotenundPC。
[CC2430-Knoten]
… Externe Parameter können regelmäßig gesammelt und an den PC gesendet werden
… Automatischer Rückstart, wenn das Gerät ausgeschaltet wird
… Befehle vom PC können entsprechend empfangen und verarbeitet werden: Änderung des Stichprobenintervalls/Energiemanagements
[PC]
… Die C-Maschine empfängt und zeigt Daten über das serielle Portwerkzeug an
… Befehle können über das serielle Port-Tool an den Mikrocontroller gesendet werden, um dessen Abtastgeschwindigkeit und Energiemanagement zu steuern
3. Detailliertes Design(1) Codestruktur
Die Schichtung der Codestruktur dieses Systems wurde tatsächlich im Aufsatz beschriebenHierarchie der eingebetteten Projektcode-Struktur", und die Kopie lautet wie folgt:
(1) Hardware-Abstraktionsschicht
[ioCC2430.h] (System enthalten):Alle SFR- und Interruptvektoren des CC2430 sind definiert
[hal.h] Enthält gängige Typdefinitionen, gängige Zuweisungsmakros und gemeinsame Konfiguration der CC2430-On-Chip-Ressourcen (I/O, serielle Kommunikation, ADC, Timer, Energiemanagement usw.)
(2) Funktionalmodulschicht
[module.h] definiert On-Chip-Ressourcen (Timer, I/O), Off-Chip-Erweiterungsmodule (LEDs) und Deklarationen verwandter Funktionen
[module.cImplementiere die Initialisierung jedes Moduls (LED).
(3) Anwendungsschicht
[main.cSiehe hal.h, ioCC2430.h und module.h, um spezifische Anwendungsanforderungen wie Temperaturerfassung, Kommunikation mit dem PC sowie Abschalten und Zurücksetzen zu erfüllen.
(2) Implementierungsmethoden jedes Moduls
Nach den Modulen, die nach dem Gliederungsdesign unterteilt sind, kann das intrinsische System in zwei Hauptmodule unterteilt werden:CC2430-KnotenundPC。
Da es auf dem PC serielle Port-Kommunikationswerkzeuge gibt, können dessen Funktionen die Anforderungen erfüllen, sodass wir diesen Teil des PCs nicht machen müssen und es nicht notwendig ist, ihn zu analysieren. Sprechen wir unten über Abschnitt CC2430
Die Implementierungsmethode jeder Unterfunktion des Punktes:
… Nutze den Count-Overflow-Interrupt des Timers, um zeitgesteuertes Sampling auszulösen
… Der UART0-Modus mit seriellem Anschluss überträgt Temperaturdaten an einen PC
… Die eingebaute Wachhundschaltung des CC2430 wird verwendet, um die automatische Reset-Funktion des Systems zu realisieren
… Der serielle Port wird verwendet, um Interrupts zu empfangen, um Steuerbefehle vom PC zu erfassen und darauf zu reagieren
1) Falls empfangen@Das Zeichen ist der Steuerbefehl für das Abtastintervall, gefolgt von einer Zahl, die das Abtastintervall angibt: 0-0,5 Sekunden, 1-1S, 2-2S
如:@0,表示每隔0.5秒采样一次。
2) Falls empfangen$ Das Zeichen ist der Schlafkontrollbefehl, gefolgt von einer Zahl, die den Energiemodus angibt
Zum Beispiel: 3 $, was bedeutet, das System in Energiemodus 3 zu versetzen.
(3) Programmflussdiagramm
- Master-Programm-Flussdiagramm
- Timer 1 Overflow-Interrupt-Programm-Flussdiagramm
- Flussdiagramm des seriellen Port-Interrupt-Verfahrens
4. Codierungsimplementierung(1) Hardware-Abstraktionsschicht
Die Hardware-Abstraktionsschicht umfasst ioCC2430.h und hal.h. Da das erstgenannte System damit ausgestattet ist, wird es nicht aufgeführt.
Im Folgenden ist eine Liste aller Inhalte von hal.h (da diese Datei zu lang ist und unpraktisch aussieht, werde ich sie in Modulen zeigen):
- Kopf
- I/O-Ports
- Unterbrochen
- Serieller Anschluss
- Strom- und Taktverwaltung
- Timer
- Wachhund
- ADC
[url=]
[/url]
/***********************************************************
*Dateiname: hal.h
*Autor: hustlzp
*Datum: 8. März 2011
*Ausgabe: 1.1
*Funktionsbeschreibung: Hardware-Abstraktionsschicht
*Geänderte Aufzeichnungen:
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Gebräuchliche Typdefinitionen
***********************************************************/
typedef unsignedchar BYTE;
typedef unsignedInt WORT;
typedef unsignedlang DWORD;
/***********************************************************
Gebräuchlich verwendete Makrodefinitionen
***********************************************************/
//8 Plätze höher
#defineHIGH_BYTE(a) ((BYTE) (((WORD)(a)) >> 8))
//8 Plätze tiefer
#defineLOW_BYTE(a) ((BYTE) ((WORD)(a)))
//Zuweisung
#defineSET_WORD(regH, regL, Wort)
tun{
(regH)=HIGH_BYTE(Wort);
(regL)=LOW_BYTE(Wort);
}während(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
I/O-Ports
***********************************************************/
/*Konfigurieren Sie die Richtung des I/O-Ports
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(Backbord, Pin, Leitung)
tun{
wenn(dir == IO_OUT)
P##port##DIR |= (0x01<<(Pin));
oder
P##port##DIR &= ~(0x01<<(Pin));
}während(0)
//Der Wert des Parameter-Dirs ist:
#defineIO_IN 0
#defineIO_OUT 1
/*Konfigurieren Sie den Eingangsmodus des I/O-Ports
-----------------------------------------*/
#defineIO_IMODE_PORT_PIN(Port, Pin, iMode)
tun{
wenn(imode == IO_IMODE_TRI)
P##port##INP |= (0x01<<(Pin));
oder
P##port##INP &= ~(0x01<<(Pin));
}während (0)
#define IO_PUD_PORT(Backbord, Pud)
tun {
wenn (pud == IO_PULLDOWN)
P2INP |= (0x01 << (Port+5));
oder
P2INP &= ~(0x01 << (port+5));
} während (0)
Der Wert des Parameters PUD lautet:
#define IO_PULLUP 0 // Zieh hoch
#define IO_PULLDOWN 1 // Nach unten ziehen
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(Port, Pin, Func)
tun {
wenn((Port == 2) && (Pin == 3)){
wenn (func) {
P2SEL |= 0x02;
} sonst {
P2SEL &= ~0x02;
}
}
else if((Port == 2) && (Pin == 4)){
wenn (func) {
P2SEL |= 0x04;
} sonst {
P2SEL &= ~0x04;
}
}
sonst{
wenn (func) {
P##port##SEL |= (0x01<<(Pin));
} sonst {
P##port##SEL &= ~(0x01<<(Pin));
}
}
} während (0)
Der Wert des Parameterfunks lautet:
#define IO_FUNC_GIO 0 // Allgemeiner I/O
#define IO_FUNC_PERIPH 1 // Peripherie-I/O
Konfigurieren Sie den Standort der peripheren I/O
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } während (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } während (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } während (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } während (0)
#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } während (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } während (0)
#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } während (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } während (0)
#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } während (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } während (0)
#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } während (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } während (0)
#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } während (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } während (0)
//Der Wert des Parameters imode lautet:
#defineIO_IMODE_PUD 0 //Hochziehen/runterziehen
#defineIO_IMODE_TRI 1 //Drei Bundesstaaten[url=] [/url]
[url=] [/url]
/***********************************************************
Unterbrochen
***********************************************************/
//Für Ein-/Aus-Unterbrechungen
#defineINT_ON 1
#defineINT_OFF 0
//Wurde verwendet, um Interrupt-Flags zu platzieren oder zu löschen
#defineINT_SET 1
#defineINT_CLR 0
//Globale Interrupt-Einstellungen
#defineINT_GLOBAL_ENABLE(an) EA=(!! an)
//Definiere den Bruch
#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
/*Erlaubte Unterbrechungen
-----------------------------------------*/
#defineINT_ENABLE(inum, an)
tun{
wenn (inum==INUM_RFERR) { RFERRIE = on; }
oder wenn(inum==INUM_ADC) { ADCIE = an; }
oder wenn(inum==INUM_URX0) { URX0IE = on; }
oder wenn(inum==INUM_URX1) { URX1IE = an; }
oder wenn(inum==INUM_ENC) { ENCIE = an; }
oder wenn(inum==INUM_ST) { STIE = an; }
oder wenn(inum==INUM_P2INT) { (an) ? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
oder wenn(inum==INUM_UTX0) { (an) ? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
oder wenn(inum==INUM_DMA) { DMAIE = an; }
oder wenn(inum==INUM_T1) { T1IE = an; }
oder wenn(inum==INUM_T2) { T2IE = an; }
oder wenn(inum==INUM_T3) { T3IE = on; }
oder wenn(inum==INUM_T4) { T4IE = an; }
oder wenn(inum==INUM_P0INT) { P0IE = an; }
oder wenn(inum==INUM_UTX1) { (an) ? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
oder wenn(inum==INUM_P1INT) { (an) ? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
oder wenn(inum==INUM_RF) { (an) ? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
oder wenn(inum==INUM_WDT) { (an) ? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}während (0)
/*Stellen Sie die Ausfallpriorität ein
-----------------------------------------*/
#defineINT_PRIORITY(Gruppe, PRI)
tun{
wenn(pri ==0) { IP0 &= ~group; IP1 &= ~gruppe; }
wenn(pri ==1) { IP0 |= Gruppe; IP1 &= ~gruppe; }
wenn(pri ==2) { IP0 &= ~group; IP1 |= Gruppe; }
wenn(pri ==3) { IP0 |= Gruppe; IP1 |= Gruppe; }
}während (0)
//Der Wert des Parameters pri ist: 0/1/2/3 (höchste Priorität)
//Der Wert der Parametergruppe ist:
#defineRFERR_RF_DMA 0x01//Gruppe IP0
#defineADC_P2INT_T1 0x02//Gruppe IP1
#defineURX0_UTX0_T2 0x04//Gruppe IP2
#defineURX1_UTX1_T3 0x08//Gruppe IP3
#defineENC_P1INT_T4 0x10//Gruppe IP4
#defineST_WDT_P0INT 0x20//Gruppe IP5
/*Hol dir das 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
)
/*Setzen Sie das Interrupt-Flag
-----------------------------------------*/
#defineINT_SETFLAG(Inum, F)
tun{
wenn (inum==INUM_RFERR) { RFERRIF= f; }
oder wenn(inum==INUM_ADC) { ADCIF = f; }
oder wenn(inum==INUM_URX0) { URX0IF = f; }
oder wenn(inum==INUM_URX1) { URX1IF = f; }
oder wenn(inum==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; }
oder wenn(inum==INUM_ST) { STIF = f; }
oder wenn(inum==INUM_P2INT) { P2IF = f; }
oder wenn(inum==INUM_UTX0) { UTX0IF= f; }
oder wenn(inum==INUM_DMA) { DMAIF = f; }
oder wenn(inum==INUM_T1) { T1IF = f; }
oder wenn(inum==INUM_T2) { T2IF = f; }
oder wenn(inum==INUM_T3) { T3IF = f; }
oder wenn(inum==INUM_T4) { T4IF = f; }
oder wenn(inum==INUM_P0INT) { P0IF = f; }
oder wenn(inum==INUM_UTX1) { UTX1IF= f; }
oder wenn(inum==INUM_P1INT) { P1IF = f; }
oder wenn(inum==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
oder wenn(inum==INUM_WDT) { WDTIF = f; }
}während (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Serieller Anschluss
***********************************************************/
//Der Wert der BAUD_E entspricht verschiedenen Baudraten
#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 )
//Der Wert der BAUD_M entspricht verschiedenen Baudraten
#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)
/*Serielle Portkonfiguration im UART-Modus
-----------------------------------------*/
#defineUART_SETUP(uart, receiveEnable, baudRate, Optionen)
tun{
wenn((uart) ==0){
wenn(PERCFG &0x01){
P1SEL |=0x30;
}oder{
P0SEL |=0x0C;
}
}
oder{
wenn(PERCFG &0x02){
P1SEL |=0xC0;
}oder{
P0SEL |=0x30;
}
}
U##uart##GCR = BAUD_E((baudRate),CLKSPD);
U##uart##BAUD = BAUD_M(baudRate);
U##uart##CSR |=0x80;
U##uart##CSR |= empfangenAktivieren;
U##uart##UCR |= ((Optionen) |0x80);
}während(0)
//Der Wert des Parameters receiveEnable:
#defineUART_RECEIVE_ENABLE 0x40 //Erhalt der Erlaubnis
#defineUART_RECEIVE_DISABLE 0x00
//Der Wert der Parameteroptionen:
#defineFLOW_CONTROL_ENABLE 0x40 //Durchflussregelung
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Gelegentliche Überprüfung
#defineODD_PARITY 0x00 //Seltsame Verifizierung
#defineNINE_BIT_TRANSFER 0x10 //9-Byte-Transfer
#defineEIGHT_BIT_TRANSFER 0x00 //8-Byte-Transfer
#definePARITY_ENABLE 0x08 //Paritätsprüfungs-Enablement
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //2-Position Stoppposition
#defineONE_STOP_BITS 0x00 //1 Stoppposition
#defineHIGH_STOP 0x02 //Das Stoppniveau ist hoch
#defineLOW_STOP 0x00 //Die Stoppposition ist niedrig
#defineHIGH_START 0x01 //Der Anfangsbitwert ist hoch
#defineLOW_START 0x00 //Der Anfangsbit-Level ist niedrig
//Serieller Port sendet Zeichen
#defineUART_SEND(uart,data)
tun{
während(U##uart##CSR &0x01);
U##uart##DBUF = Daten;
}während (0)
#defineUART0_SEND(Daten) UART_SEND(0,Daten)
#defineUART1_SEND(data) UART_SEND(1,data)
//Serieller Port erhält Zeichen
#defineUART_RECEIVE(uart,data)
tun{
während(! (U##uart##CSR&0x04));
data=U##uart##DBUF;
}während(0)
#defineUART0_RECEIVE(Daten) UART_RECEIVE(0,Daten)
#defineUART1_RECEIVE(Daten) UART_RECEIVE(1,Daten)
[url=] [/url]
[url=] [/url]
/***********************************************************
Strom- und Taktverwaltung
***********************************************************/
//Hol dir das Uhr-Crossover
#defineCLKSPD (CLKCON & 0x07)
//Stellen Sie den Energiemodus ein
#defineSET_POWER_MODE(Modus)
tun{
wenn(Modus ==0) { SCHLAF &= ~0x03; }
oder wenn(Modus ==3) { SCHLAF |=0x03; }
oder{ SCHLAF &= ~0x03; SLEEP |= Modus; }
PCON |=0x01;
ASM("NOP");
}während (0)
//Der Parametermodus wird auf folgende Werte gesetzt:
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Verwendet zur Erkennung der Stabilität von hochfrequenten RC-Oszillatoren
#defineHIGH_FREQUENCY_RC_OSC_STABLE (SCHLAF & 0x20)
//Verwendet zur Erkennung des stabilen Zustands des Kristalloszillators
#defineXOSC_STABLE (SCHLAF & 0x40)
//Erhalten Sie den Tickfrequenzwert des Timers
#defineTICKSPD ((CLKCON & 0x38) >> 3)
//Stellen Sie die Haupttaktfrequenz ein
#defineSET_MAIN_CLOCK_SOURCE(Quelle)
tun{
wenn(Quelle) {
CLKCON |=0x40;
während(! HIGH_FREQUENCY_RC_OSC_STABLE);
wenn(TICKSPD ==0){
CLKCON |=0x08;
}
SCHLAF |=0x04;
}
oder{
SCHLAF &= ~0x04;
während(! XOSC_STABLE);
ASM("NOP");
CLKCON &= ~0x47;
SCHLAF |=0x04;
}
}während (0)
//Der Wert der Parameterquelle lautet:
#defineCRYSTAL 0x00 //Kristalloszillator
#defineRC 0x01 //RC-Oszillator
[url=] [/url]
[url=] [/url]
/***********************************************************
Timer 1
***********************************************************/
//Timer 1 ermöglicht es, dass der Zählüberlauf unterbrochen wird
#defineTIMER1_ENABLE_OVERFLOW_INT(Val)
(TIMIF = (Val)? TIMIF |0x40: TIMIF & ~0x40)
//Setze das Overflow-Interrupt-Flag für Timer 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Timer 1 startet
#defineTIMER1_RUN(Wert) (T1CTL = (Wert) ? T1CTL|0x02 : T1CTL&~0x03)
//Stelle die Uhrendivision für den Timer ein
#defineSET_TIMER_TICK(Wert) do{ CLKCON = ((CLKCON & (~0x38)) | Wert); } während(0)
//Der Wert des Wertes ist:
#defineTIMER1_TICK_32M 0x00 //32 MHz
#defineTIMER1_TICK_16M 0x08 //16 MHz, der Standardwert für den Systemreset
#defineTIMER1_TICK_8M 0x10 //8 MHz
#defineTIMER1_TICK_4M 0x18 //4 MHz
#defineTIMER1_TICK_2M 0x20 //2 MHz
#defineTIMER1_TICK_1M 0x28 //1 MHz
#defineTIMER1_TICK_500k 0x30 //500kHz
#defineTIMER1_TICK_250k 0x38 //250 kHz
//Stellen Sie die TICK-Weiche auf Timer 1 ein
#defineSET_TIMER1_TICKDIV(Wert)
tun{
T1CTL &= ~0x0c;
T1CTL |= Wert;
}während (0)
//wobei der Wert lautet:
#defineTIMER1_TICKDIV_1 0x00 //1. Division
#defineTIMER1_TICKDIV_8 0x04 //8-Wege-Frequenz
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Stellen Sie die Überlaufzeit des Timers ein
#defineSET_TIMER1_PERIOD(Wert)
tun{
T1CC0H = HIGH_BYTE(Wert);
T1CC0L = LOW_BYTE(Wert);
}während (0)
//Stellen Sie den Betriebsmodus von Timer 1 ein
#defineSET_TIMER1_MODE(Modus)
tun{
T1CTL = ((T1CTL & (~0x03)) | Modus);
}während (0)
//Der Wert von Modus lautet:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Wachhund
***********************************************************/
//Stellen Sie die Überlaufzeit für den Wachhund-Timer ein
#defineWDT_SET_TIMEOUT_PERIOD(Auszeit)
tun{ WDCTL &= ~0x03; WDCTL |= Auszeit; }während (0)
//Der Wert des Parameter-Timeouts lautet:
#defineSEC_1 0x00 //Nach 1 Sekunde
#defineM_SEC_250 0x01 //nach 250 ms
#defineM_SEC_15 0x02 //Nach 15 ms
#defineM_SEC_2 0x03 //Nach 2 ms
//Hundefütterungsverfahren
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} während (0)
//Start/Stopp des Wachhund-Timers
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Konfigurieren Sie einen einzelnen ADC
#defineADC_SINGLE_CONVERSION(Einstellungen)
tun{ ADCCON3 = Einstellungen; }während(0)
//Die Parametereinstellung setzt sich aus folgenden Kombinationen zusammen:
//Referenzspannung
#defineADC_REF_1_25_V 0x00 //Interne 1,25 V Referenzspannung
#defineADC_REF_P0_7 0x40 //Externe Referenzspannung am AIN7-Pin
#defineADC_REF_AVDD 0x80 //AVDD_SOC Pins
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 Externe Referenzspannung für differentielle Eingänge
//Abtastrate
#defineADC_8_BIT 0x00 //8. Platz
#defineADC_10_BIT 0x10 //10. Platz
#defineADC_12_BIT 0x20 //12. Platz
#defineADC_14_BIT 0x30 //14. Platz
//Betreten Sie den Kanal
#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-Temperatursensor
#defineADC_VDD_3 0x0F //VDD/3
Die ADC-Umstellung ist abgeschlossen
#define ADC_SAMPLE_READY() (ADCCON1 & 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40; } während (0)//Wählen Sie den Trigger-Modus des ADCs manuell (also ADC_SAMPLE_READY) aus.
#defineADC_STOP()
tun{ ADCCON1 |=0x30; }während (0)[url=] [/url]
(2) Funktionalmodulschicht
[url=] [/url]
/***********************************************************
*Dateiname: module.h
*Autor: hustlzp
*Datum: 6. März 2011
*Version: 1.0
*Funktionsbeschreibung: Funktionale Modul-Layer-Header-Datei
*Funktionsliste: Void led_init()
Void timer1_init()
Void uart0_init(Void);
void Uart0SendString (unsigned character *s);
Float adc_start(Leere)
void get_temperature(unsigned char *output, float-temperatur);
Void watchdog_init(Void);
*Geänderte Aufzeichnungen:
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Definieren Sie die LED-Pins
#defineled1 P1_0
#defineled2 P1_1
#defineled3 P1_2
#defineled4 P1_3
//LED-Licht und aus
#defineLED_OFF 1
#defineLED_ON 0
//LED-Initialisierung
Leereled_init(Leere);
/***********************************************************
Timer1
***********************************************************/
//Verwendet zum Festlegen des Überlaufzeitraums für den Timer
#defineTIMER1_OVF_2SEC 0xF424 //2S
#defineTIMER1_OVF_1SEC 0x7A12 //1s
#defineTIMER1_OVF_dot5SEC 0x3D09 //0,5 Sekunden
//Timer 1 initialisiert
Leere timer1_init(Leere);
/***********************************************************
UART0
***********************************************************/
//UART0-Initialisierung
Leere uart0_init(Leere);
//Seriell-Port-Übertragungsstring
Leere Uart0SendString (unsignedchar*s);
/***********************************************************
ADC-14
***********************************************************/
//Verwendet zur Umwandlung der vom ADC gewonnenen Daten in Celsius-Temperatur
#defineADC_TO_CELSIUS(Temp) (Temp * 0,06229 - 311,43)
//ADC-Umstellung einleiten
schwebenadc_start(Leere);
//Umbau
Leere get_temperature(unsigniert)char*Ausgabe,schwebenvorübergehend);
/***********************************************************
WatchDog
***********************************************************/
//Wachhund-Initialisierung
Leere watchdog_init(Leere);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*Dateiname: module.c
*Autor: hustlzp
*Datum: 2011.03.11
*Version: 1.0
*Funktionsbeschreibung: Quelldatei der funktionalen Modulschicht
*Funktionsliste: (weggelassen)
*Geänderte Aufzeichnungen:
***********************************************************/
#include"module.h"
/***********************************************************
*Funktionsname: led_init
*Funktionsfunktion: LED-Initialisierung
*Eingangsparameter: Keine
*Exportparameter: Keine
***********************************************************/
Leereled_init(Leere)
{
//Konfigurieren Sie P1.0, P1.1, P1.2 und P1.3 als allgemeine 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);
//Konfigurieren Sie P1.0, P1.1, P1.2 und P1.3 als Ausgaben
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;
}
/***********************************************************
*Funktionsname: timer1_init
* Funktionsfunktion: Timer 1 Initialisierung
*Eingangsparameter: Keine
*Exportparameter: Keine
***********************************************************/
Leeretimer1_init(Leere)
{
INT_GLOBAL_ENABLE(INT_ON); //Öffne die globale Unterbrechung
INT_ENABLE(INUM_T1, INT_ON); //Offener T1-Interrupt
TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //Offener T1-Zählüberlauf-Interrupt
SET_TIMER_TICK(TIMER1_TICK_4M); //Stell den Timer TICK auf 4 MHz
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //Setze die Zählzeit für T1 auf 2s
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //Stelle die Taktfrequenzweiche für T1 auf 128 ein
SET_TIMER1_MODE(TIMER1_MODE_MODULE); //Stellen Sie den Betriebsmodus von T1 auf Modul ein
}
/***********************************************************
*Funktionsname: uart0_init
*Funktionsfunktion: Serielle UART0-Initialisierung
*Eingangsparameter: Keine
*Exportparameter: Keine
***********************************************************/
Leereuart0_init(Leere)
{
//Wählen Sie den UART-Standort aus
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//UART konfigurieren: Empfang erlaubt, 115200 bps, Ein-Bit-Stoppbit, keine Parität
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);
//Öffne die totale Unterbrechung
INT_GLOBAL_ENABLE(INT_ON);
//Seriellen Port 0 öffnen, um Interrupts zu empfangen
INT_ENABLE(INUM_URX0, INT_ON);
}
/***********************************************************
*Funktionsname: Uart0SendString
* Funktionsfunktion: Timer 1 Initialisierung
*Eintragsparameter: unsigned char *s
Die Zeichenkette, die du senden möchtest
*Exportparameter: Keine
***********************************************************/
LeereUart0SendString (unsignedchar*s)
{
während(*s !=0)
UART0_SEND(*s++);
}
/***********************************************************
*Funktionsname: adc_start
*Funktionsfunktion: Start ADC-Konvertierung
*Eingangsparameter: Keine
*Exportparameter: float
Der Temperaturwert in der Tablette
***********************************************************/
schwebenadc_start(Leere)
{
UnsigniertIntTemp;
//Die Referenzspannung beträgt 1,25 V, die Abtastgenauigkeit 14 Bit, und das Umwandlungsziel ist der On-Chip-Temperatursensor
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
ADC_STOP(); //Stellen Sie die Trigger-Methode für die ADC-Umwandlung auf manuell ein
ADC_START(); //ADC-Umstellung einleiten
während(! ADC_SAMPLE_READY()); //Warte, bis die Umwandlung abgeschlossen ist
temp = ADCL >>2; //Speichert man die Umwandlung, ergibt es die Temperatur
temp |= (((unsignedInt) ADCH) <<6);
RückgabeADC_TO_CELSIUS(temporär); //Gibt nach der Umwandlung den tatsächlichen Temperaturwert zurück
}
/***********************************************************
*Funktionsname: get_temperature
*Funktionsfunktion: Verarbeiten Sie den Temperaturwert und speichern Sie ihn im Zeichenarray für die serielle Ausgabe
*Eintragsparameter: unsigned char *Ausgabe
Zur Speicherung des umgewandelten Temperaturwerts verwendet
Schwimmertemperatur
Celsius-Temperaturwert
*Exportparameter: Keine
***********************************************************/
Leereget_temperature(unsigniert)char*Ausgabe,schwebenTemp)
{
Ausgabe[0] = (unsigniertchar(temporär) /10 + 48; //Zehn Orte
Ausgabe[1] = (unsigniertchar(Temp) %10 + 48; //Einstellige Zahl
Ausgabe[2] ='.'; //Dezimalkommatikum
Ausgabe[3] = (unsigniertchar(temp*10) %10 + 48; //Zehntes
Ausgabe[4] = (unsigniertchar(temp*100) %10 + 48; //Perzentil
Ausgabe[5] =''; //String-Endifikatoren
}
/***********************************************************
*Funktionsname: watchdog_init
*Funktionsfunktion: Watch Dog Initialisierung
*Eingangsparameter: Keine
*Exportparameter: Keine
***********************************************************/
Leerewatchdog_init(Leere)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1); //Setze die Auszeitzeit auf 1 Sekunden
WDT_ENABLE(); //Starte den Wachhund
}
[url=] [/url]
(3) Anwendungsschicht
[url=] [/url]
/*******************************************************************
Dateiname: main.c
Autor: hustlzp
Datum: 2011.03.11
Version: 1.0
Funktionsbeschreibung: Masterprogrammdatei
Funktionsliste: (weggelassen)
Modifikationsnachweis:
*******************************************************************/
#include
/********************************************************************
Interrupt-Service-Prozeduren
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma Vektor=T1_VECTOR
__interrupt Void T1_ISR(Void)
{
EA=0; Das Tor wird unterbrochen
led2 = LED_ON;
get_temperature(Ausgabe,adc_start()); Konvertiere den Temperaturwert in ein Array von Zeichen, die ausgegeben werden sollen
Uart0SendString(output); Ausgangstemperaturwert
Uart0SendString("°C");
led2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma Vektor=URX0_VECTOR
__interrupt Void RE_ISR(Void)
{
EA=0;
led3 = LED_ON;
empfangen = U0DBUF;
if(type==1) // type=1, was anzeigt, dass das empfangene Zeichen verwendet wird, um den Timer-Überlaufzeitraum einzustellen
{
Typ=0;
Wechsel (Empfang)
{
Fall '0': // Timer-Überlaufzeitraum beträgt 0,5 Sekunden
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
Unterbrechung;
}
Fall '1': // Timer-Überlaufzeit beträgt 1 Sekunden
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
Unterbrechung;
}
Fall '2': // Timer-Überlaufzeitraum beträgt 2 Sekunden
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
Unterbrechung;
}
}
}
else if(type==2) // type=2, was darauf hinweist, dass die empfangenen Zeichen für die Schlafkontrolle verwendet werden
{
Typ=0;
led1 = LED_OFF;
led2 = LED_OFF;
led3 = LED_OFF;
Wechsel (Empfang)
{
Gehäuse '1': // Einschalten des Energiemodus PM1
{
SET_POWER_MODE(1);
Unterbrechung;
}
Gehäuse '2': // Schalte den Energiemodus PM2 ein
{
SET_POWER_MODE(2);
Unterbrechung;
}
Gehäuse '3': //Einschalten des Power-Modus PM3
{
SET_POWER_MODE(3);
Unterbrechung;
}
}
}
else if(type==0) // type=0, was anzeigt, dass das empfangene Zeichen der Typ des Steuerbefehls ist: @ oder $
{
if(empfang=='@')
{
Typ=1; '@' wird empfangen, um anzuzeigen, dass das nächste Zeichen zur Einstellung der Überlaufperiode verwendet wird
}
else if(empfang=='$')
{
type=2; '$' wird empfangen, was anzeigt, dass das nächste Zeichen für die System-Schlafkontrolle verwendet wird
}
}
led3 = LED_OFF;
EA=1;
}
=LED_OFF;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR); Löschen Sie das Unterbrechungsschild
EA=1; Offene Unterbrechung
}
/* 主函数
-------------------------------------------------------*/
Void Main (Void)
{
SET_MAIN_CLOCK_SOURCE(KRISTALL); Stellen Sie den Systemtakt auf 32 MHz Quarzoszillator ein
led_init(); LED-Initialisierung
uart0_init(); Seriell-Port UART0-Initialisierung
timer1_init(); Timer 1 initialisiert
watchdog_init(); Wachhund-Initialisierung
während(1)
{
WDT_RESET(); Füttere den Hund ständig
}
}/********************************************************************
Hauptprogramm
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
unsigned char output[6]={0}; Temperaturdaten werden für eine einfache serielle Ausgabe gespeichert.
unsignierte Char empfangen; Speichern Sie die empfangenen Zeichen
unsignierter Zeichentyp=0; Das Typ-Flag des empfangenen Zeichens ist auf 0/1/2 gesetzt"module.h"[url=] [/url]
5. TestsOh~ Der Code ist endlich eingefügt, es ist wirklich anstrengend, lass uns dieses kleine System testen:
(1) Zeitbegrenzung
Öffnen Sie den seriellen Port und beginnen Sie mit dem IAR-Debugging, stellen Sie fest, dass LED1 eingeschaltet ist und der Temperaturwert auf dem seriellen Port-Werkzeug ständig generiert wird, wobei das Abtastintervall auf 2 Sekunden festgelegt wird:
(2) Abtastintervallsteuerung
Geben Sie "@1" im seriellen Port-Werkzeug ein und testen Sie dann das Abtastintervall, wobei es zu 1s geworden ist; Gibt man "@0" ein, hat sich das Abtastintervall auf 0,5 Sekunden geändert.
(3) Schlafkontrolle
Geben Sie im seriellen Port-Tool "$1" ein und stellen fest, dass alle LEDs aus sind und die Temperaturprobe gestoppt ist:
Nach dem Test funktioniert das System normal und stabil und erfüllt im Grunde die Anforderungen.
Schüler, die Quellcode benötigenKlicken Sie hier, um sie herunterzuladen
6. FazitDieses Paper nimmt ein etwas umfassendes Experiment als Beispiel, um zu zeigen, wie CC2430 On-Chip-Ressourcen integriert werden können, um ein relativ standardisiertes kleines System zu schreiben. In ein paar Tagen werde ich mir die Zeit nehmen, ein einfaches Benutzerhandbuch für hal.h zu schreiben, damit ich und alle anderen den CC2430 problemlos bedienen können.
Als Nächstes werde ich meine Recherche zu CC2430 On-Chip-Ressourcen abschließen und mich dem Lernen des TI Z-Stack Protokollstacks widmen~
Der Blogbeitrag in dieser Serie ist vorerst beendet, aber Zigbees Reise wird weitergehen. Die Landschaft vor uns ist unbekannt, aber ich glaube, dass der Autor mit allen Hindernissen überwinden und die Höhen und Tiefen schmecken wird, und es wird Vorteile geben.
Bleiben Sie dran: "Join TI Z-Stack"-Blogbeiträge!