После написания книги «Zigbee Journey (9)» 3 марта автор изначально планировал немедленно начать небольшой эксперимент по «системе мониторинга температуры» как краткое изложение серии разбросанных точек знаний, ранее встречавшихся. Однако я также понял, что хотя каждый из предыдущих небольших экспериментов был подробно описан, нормативный и структурный характер его кода можно назвать невыносимым. Поскольку это резюме, нам следует двигаться вперёд на исходной основе, а не механически собирать предыдущие мелкие знания. Поэтому я отложил свой первоначальный план, потратил время на изучение общих техник встроенной разработки и написал два эссеВстроенная спецификация программирования C51" и "Иерархия встроенной структуры кода проекта》。 Этот журнал не только представляет собой краткое изложение первой поездки Zigbee, но и включает опыт автора в последние дни, надеясь быть полезным новичкам в Zigbee.
Полный текст организован в соответствии с базовым процессом разработки программного обеспечения: анализ требований, проектирование контуров, детальное проектирование, реализация кода и тестирование.
1. Анализ спросаПосле обсуждения между «заказчиком» и «разработчиком» было определено следующее описание функции системы:
… Текущая комнатная температура собирается узлами на базе CC2430, и её значения температуры можно контролировать через ПК
… Сам узел CC2430 должен обладать определённой степенью стабильности и может автоматически возвращаться в нормальное состояние
… Интервал дискретизации и управление энергопотреблением узла могут контролироваться ПК
2. Дизайн контуровСогласно вышеуказанному анализу требований, систему можно разделить на два модуля:узел CC2430иPC。
[узел CC2430]
… Внешние параметры можно регулярно собирать и отправлять на ПК
… Автоматический сброс при выключении машины
… Команды с ПК могут быть получены и обработаны соответствующим образом: изменение интервала сэмпла/управления энергопотреблением
[ПК]
… Машина C принимает и отображает данные через инструмент последовательного порта
… Инструкции могут быть отправлены микроконтроллеру через инструмент последовательного порта для управления скоростью дискретизации и управления энергопотреблением
3. Детальное проектирование(1) Структура кода
Многослойность структуры кода этой системы на самом деле была описана в эссе «Иерархия встроенной структуры кода проекта», а копия выглядит следующим образом:
(1) Аппаратный уровень абстракции
[ioCC2430.h] (система включена):Все SFR и векторы прерывания CC2430 определены
[hal.h] Включает общие определения типов, распространённые макросы назначения и общую конфигурацию ресурсов на чипе CC2430 (ввод/вывод, последовательная связь, АЦП, таймер, управление питанием и др.)
(2) Функциональный модульный слой
[module.h] определяет встроенные ресурсы (таймеры, ввод-вывод), модули расширения вне чипа (LED) и объявления связанных функций
[module.cРеализуйте инициализацию каждого модуля (LED).
(3) Прикладной уровень
[main.cОбратитесь к hal.h, ioCC2430.h и module.h для достижения конкретных требований, таких как оценка температуры, взаимодействие с ПК, а также отключение и сброс
(2) Методы реализации каждого модуля
В соответствии с модулями, разделёнными по контурному дизайну, внутренняя система может быть разделена на два основных модуля:узел CC2430иPC。
Поскольку на ПК есть инструменты связи с последовательными портами, его функции могут соответствовать требованиям, поэтому нам не нужно делать эту часть ПК и анализировать её нет. Давайте поговорим о разделе CC2430 ниже
Метод реализации каждой подфункции точки:
… Используйте прерывание переполнения таймера для запуска таймерного отбора проб
… Режим UART0 с последовательным портом передаёт температурные данные на ПК
… Встроенная схема watchdog CC2430 используется для реализации функции автоматического сброса системы
… Последовательный порт используется для приема прерываний, чтобы захватить и реагировать на команды управления с ПК
1) Если получено@Символ — это команда управления интервалом дискретизации, за которой следует число, указывающее интервал дискретизации: 0-0,5с, 1-1с, 2-2с
如:@0,表示每隔0.5秒采样一次。
2) Если получено$ Символом является команда управления сном, за которой следует цифра, указывающая режим питания
Например: $3, что означает перевести систему в режим питания 3.
(3) Блок-схема программы
- Блок-схема мастер-программ
- Блок-схема переполнения программы прерывания таймера 1
- Блок-схема процедуры прерывания, принимающего последовательные порты
4. Реализация кодирования(1) Аппаратный уровень абстракции
Аппаратный уровень абстракции включает ioCC2430.h и hal.h. Поскольку первая система идёт в комплекте, она не будет указана в списке.
Ниже приведён список всего содержимого hal.h (поскольку этот файл слишком длинный и выглядит неудобным, я покажу его в модулях):
- Голова
- Порты ввода/вывода
- Прерван
- Последовательный порт
- Управление питанием и тактовыми частотами
- Таймер
- Сторожевой пёс
- ADC
[url=]
[/url]
/***********************************************************
*Имя файла: hal.h
*Автор: hustlzp
*Дата: 8 марта 2011 года
*Издание: 1.1
*Описание функции: Аппаратный абстракционный слой
*Изменённые записи:
***********************************************************/
#ifndef HAL_H
#defineHAL_H
#include
/***********************************************************
Распространённые определения типов
***********************************************************/
typedef unsignedЧар BYTE;
typedef unsignedint СЛОВО;
typedef unsignedДолго DWORD;
/***********************************************************
Часто используемые определения макро
***********************************************************/
//На 8 позиций выше
#defineHIGH_BYTE(a) ((БАЙТ) (((WORD)(a)) >> 8))
//На 8 позиций ниже
#defineLOW_BYTE(a) ((БАЙТ) ((WORD)(a)))
//Назначение
#defineSET_WORD(regH,regL,word)
делать{
(regH)=HIGH_BYTE(слово);
(regL)=LOW_BYTE(слово);
}в то время как(0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Порты ввода/вывода
***********************************************************/
/*Настройте направление порта ввода/вывода
-----------------------------------------*/
#defineIO_DIR_PORT_PIN(порт, пин, режиссура)
делать{
если(реж. == IO_OUT)
P##port##DIR |= (0x01<<(штифт));
Другое
P##port##DIR &= ~(0x01<<(штифт));
}в то время как(0)
//Значение параметра dir равно:
#defineIO_IN 0
#defineIO_OUT 1
/*Настройте режим ввода порта ввода/вывода
-----------------------------------------*/
#defineIO_IMODE_PORT_PIN(порт, PIN, iMode)
делать{
если(iMode == IO_IMODE_TRI)
P##port##INP |= (0x01<<(штифт));
Другое
P##port##INP &= ~(0x01<<(штифт));
}в то время как (0)
#define IO_PUD_PORT(порт, пуд)
do {
если (pud == IO_PULLDOWN)
P2INP |= (0x01 << (порт+5));
Другое
P2INP &= ~(0x01 << (порт+5));
} в то время как (0)
Значение параметра PUD равно:
#define IO_PULLUP 0 // Подтяни
#define IO_PULLDOWN 1 // Тяни вниз
/*配置I/O口的功能
-----------------------------------------*/
#define IO_FUNC_PORT_PIN(порт, пин, фанк)
do {
if((порт == 2) && (вывод == 3)){
if (func) {
P2SEL |= 0x02;
} else {
P2SEL &= ~0x02;
}
}
иначе if((порт == 2) && (вывод == 4)){
if (func) {
P2SEL |= 0x04;
} else {
P2SEL &= ~0x04;
}
}
else{
if (func) {
P##port##SEL |= (0x01<<(пин));
} else {
P##port##SEL &= ~(0x01<<(штифт));
}
}
} в то время как (0)
Значение параметра func равно:
#define IO_FUNC_GIO 0 // Общий I/O
#define IO_FUNC_PERIPH 1 // Периферийный ввод/вывод
Настройка расположения периферийного устройства ввода-вывода
#define IO_PER_LOC_TIMER1_AT_PORT0_PIN234() do { PERCFG = (PERCFG&~0x40)|0x00; } в то время как (0)
#define IO_PER_LOC_TIMER1_AT_PORT1_PIN012() do { PERCFG = (PERCFG&~0x40)|0x40; } в то время как (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN34() do { PERCFG = (PERCFG&~0x20)|0x00; } в то время как (0)
#define IO_PER_LOC_TIMER3_AT_PORT1_PIN67() do { PERCFG = (PERCFG&~0x20)|0x20; } в то время как (0)
#define IO_PER_LOC_TIMER4_AT_PORT1_PIN01() do { PERCFG = (PERCFG&~0x10)|0x00; } в то время как (0)
#define IO_PER_LOC_TIMER4_AT_PORT2_PIN03() do { PERCFG = (PERCFG&~0x10)|0x10; } в то время как (0)
#define IO_PER_LOC_SPI1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x08)|0x00; } в то время как (0)
#define IO_PER_LOC_SPI1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x08)|0x08; } в то время как (0)
#define IO_PER_LOC_SPI0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x00; } в то время как (0)
#define IO_PER_LOC_SPI0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x04)|0x04; } в то время как (0)
#define IO_PER_LOC_UART1_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x02)|0x00; } в то время как (0)
#define IO_PER_LOC_UART1_AT_PORT1_PIN4567() do { PERCFG = (PERCFG&~0x02)|0x02; } в то время как (0)
#define IO_PER_LOC_UART0_AT_PORT0_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x00; } в то время как (0)
#define IO_PER_LOC_UART0_AT_PORT1_PIN2345() do { PERCFG = (PERCFG&~0x01)|0x01; } в то время как (0)
//Значение параметра imode равно:
#defineIO_IMODE_PUD 0 //Подтягивай/тяни вниз
#defineIO_IMODE_TRI 1 //Три штата[url=] [/url]
[url=] [/url]
/***********************************************************
Прерван
***********************************************************/
//Для прерываний включения/выключения
#defineINT_ON 1
#defineINT_OFF 0
//Используется для установки/очистки флагов прерывания
#defineINT_SET 1
#defineINT_CLR 0
//Глобальные настройки прерываний
#defineINT_GLOBAL_ENABLE(включено) EA=(!! on)
//Определите разрыв
#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
/*Разрешённые прерывания
-----------------------------------------*/
#defineINT_ENABLE(инум, включено)
делать{
если (инум==INUM_RFERR) { RFERRIE = включено; }
Другое если(инум==INUM_ADC) { ADCIE = on; }
Другое если(инум==INUM_URX0) { URX0IE = включено; }
Другое если(инум==INUM_URX1) { URX1IE = on; }
Другое если(инум==INUM_ENC) { ENCIE = on; }
Другое если(инум==INUM_ST) { STIE = on; }
Другое если(инум==INUM_P2INT) { (on) ? (IEN2 |=0x02) : (IEN2 &= ~0x02); }
Другое если(инум==INUM_UTX0) { (on) ? (IEN2 |=0x04) : (IEN2 &= ~0x04); }
Другое если(инум==INUM_DMA) { DMAIE = on; }
Другое если(инум==INUM_T1) { T1IE = включено; }
Другое если(инум==INUM_T2) { T2IE = включено; }
Другое если(инум==INUM_T3) { T3IE = включено; }
Другое если(инум==INUM_T4) { T4IE = включено; }
Другое если(инум==INUM_P0INT) { P0IE = включено; }
Другое если(инум==INUM_UTX1) { (on) ? (IEN2 |=0x08) : (IEN2 &= ~0x08); }
Другое если(инум==INUM_P1INT) { (on) ? (IEN2 |=0x10) : (IEN2 &= ~0x10); }
Другое если(инум==INUM_RF) { (on) ? (IEN2 |=0x01) : (IEN2 &= ~0x01); }
Другое если(инум==INUM_WDT) { (on) ? (IEN2 |=0x20) : (IEN2 &= ~0x20); }
}в то время как (0)
/*Установить приоритет отключения
-----------------------------------------*/
#defineINT_PRIORITY(группа, Pri)
делать{
если(pri ==0) { IP0 &= ~group; IP1 &= ~группа; }
если(pri ==1) { IP0 |= группа; IP1 &= ~группа; }
если(pri ==2) { IP0 &= ~group; IP1 |= группа; }
если(pri ==3) { IP0 |= группа; IP1 |= группа; }
}в то время как (0)
//Значение параметра pri: 0/1/2/3 (высший приоритет)
//Значение группы параметров равно:
#defineRFERR_RF_DMA 0x01//Групповой IP0
#defineADC_P2INT_T1 0x02//Группа IP1
#defineURX0_UTX0_T2 0x04//Группа IP2
#defineURX1_UTX1_T3 0x08//Группа IP3
#defineENC_P1INT_T4 0x10//Группа IP4
#defineST_WDT_P0INT 0x20//Группа IP5
/*Получите флаг прерывания
-----------------------------------------*/
#defineINT_GETFLAG(инум) (
(инум==INUM_RFERR) ? RFERRIF :
(инум==INUM_ADC) ? ADCIF :
(инум==INUM_URX0) ? URX0IF :
(инум==INUM_URX1) ? URX1IF :
(инум==INUM_ENC) ? ENCIF_0 :
(инум==INUM_ST) ? STIF :
(инум==INUM_P2INT) ? P2IF :
(инум==INUM_UTX0) ? UTX0IF :
(инум==INUM_DMA) ? DMAIF :
(инум==INUM_T1) ? T1IF :
(инум==INUM_T2) ? T2IF :
(инум==INUM_T3) ? T3IF :
(инум==INUM_T4) ? T4IF :
(инум==INUM_P0INT) ? P0IF :
(инум==INUM_UTX1) ? UTX1IF :
(инум==INUM_P1INT) ? P1IF :
(инум==INUM_RF) ? S1CON &= ~0x03 :
(инум==INUM_WDT) ? WDTIF :
0
)
/*Установите флаг прерывания
-----------------------------------------*/
#defineINT_SETFLAG(инум, ф)
делать{
если (инум==INUM_RFERR) { RFERRIF= f; }
Другое если(инум==INUM_ADC) { ADCIF = f; }
Другое если(инум==INUM_URX0) { URX0IF = f; }
Другое если(инум==INUM_URX1) { URX1IF = f; }
Другое если(инум==INUM_ENC) { ENCIF_1 = ENCIF_0 = f; }
Другое если(инум==INUM_ST) { STIF = f; }
Другое если(инум==INUM_P2INT) { P2IF = f; }
Другое если(инум==INUM_UTX0) { UTX0IF= f; }
Другое если(инум==INUM_DMA) { DMAIF = f; }
Другое если(инум==INUM_T1) { T1IF = f; }
Другое если(инум==INUM_T2) { T2IF = f; }
Другое если(инум==INUM_T3) { T3IF = f; }
Другое если(инум==INUM_T4) { T4IF = f; }
Другое если(инум==INUM_P0INT) { P0IF = f; }
Другое если(инум==INUM_UTX1) { UTX1IF= f; }
Другое если(инум==INUM_P1INT) { P1IF = f; }
Другое если(инум==INUM_RF) { (f) ? (S1CON |=0x03) : (S1CON &= ~0x03); }
Другое если(инум==INUM_WDT) { WDTIF = f; }
}в то время как (0)
[url=] [/url]
[url=] [/url]
/***********************************************************
Последовательный порт
***********************************************************/
//Значение BAUD_E соответствует различным скоростям передачи
#defineBAUD_E(бауд, клкDivPow) (
(бод==2400) ? 6 +clkDivPow :
(бод==4800) ? 7 +clkDivPow :
(бод==9600) ? 8 +clkDivPow :
(бод==14400) ? 8 +clkDivPow :
(бод==19200) ? 9 +clkDivPow :
(бод==28800) ? 9 +clkDivPow :
(бод==38400) ? 10+clkDivPow :
(бод==57600) ? 10+clkDivPow :
(бод==76800) ? 11+clkDivPow :
(бод==115200) ? 11+clkDivPow :
(бод==153600) ? 12+clkDivPow :
(бод==230400) ? 12+clkDivPow :
(бод==307200) ? 13+clkDivPow :
0 )
//Значение BAUD_M соответствует различным скоростям передачи
#defineBAUD_M(бод) (
(бод==2400) ? 59 :
(бод==4800) ? 59 :
(бод==9600) ? 59 :
(бод==14400) ? 216 :
(бод==19200) ? 59 :
(бод==28800) ? 216 :
(бод==38400) ? 59 :
(бод==57600) ? 216 :
(бод==76800) ? 59 :
(бод==115200) ? 216 :
(бод==153600) ? 59 :
(бод==230400) ? 216 :
(бод==307200) ? 59 :
0)
/*Конфигурация последовательных портов в режиме UART
-----------------------------------------*/
#defineUART_SETUP(uart, receiveEnable, baudRate, options)
делать{
если((uart) ==0){
если(PERCFG &0x01){
P1SEL |=0x30;
}Другое{
P0SEL |=0x0C;
}
}
Другое{
если(PERCFG &0x02){
P1SEL |=0xC0;
}Другое{
P0SEL |=0x30;
}
}
U##uart##GCR = BAUD_E((baudRate),CLKSPD);
U##uart##BAUD = BAUD_M(baudRate);
U##uart##CSR |=0x80;
U##uart##CSR |= получитьВключить;
U##uart##UCR |= ((опции) |0x80);
}в то время как(0)
//Значение параметра receiveEnable:
#defineUART_RECEIVE_ENABLE 0x40 //Получение разрешения
#defineUART_RECEIVE_DISABLE 0x00
//Значение параметров:
#defineFLOW_CONTROL_ENABLE 0x40 //Управление потоком
#defineFLOW_CONTROL_DISABLE 0x00
#defineEVEN_PARITY 0x20 //Периодические проверки
#defineODD_PARITY 0x00 //Странная проверка
#defineNINE_BIT_TRANSFER 0x10 //9-байтовая передача
#defineEIGHT_BIT_TRANSFER 0x00 //8-байтовая передача
#definePARITY_ENABLE 0x08 //Активация проверки чётности
#definePARITY_DISABLE 0x00
#defineTWO_STOP_BITS 0x04 //2-позиционная стоп-позиция
#defineONE_STOP_BITS 0x00 //1 стоп-позиция
#defineHIGH_STOP 0x02 //Уровень стопа высокий
#defineLOW_STOP 0x00 //Положение стопа низкое
#defineHIGH_START 0x01 //Начальный уровень бита высокий.
#defineLOW_START 0x00 //Начальный уровень бита низкий
//Серийный порт отправляет персонажей
#defineUART_SEND(uart,data)
делать{
в то время как(U##uart##CSR &0x01);
U##uart##DBUF = данные;
}в то время как (0)
#defineUART0_SEND(данные) UART_SEND(0,данные)
#defineUART1_SEND(данные) UART_SEND(1,данные)
//Серийный порт принимает символы
#defineUART_RECEIVE(uart,data)
делать{
в то время как(! (U##uart##CSR&0x04));
data=U##uart##DBUF;
}в то время как(0)
#defineUART0_RECEIVE(данные) UART_RECEIVE(0,данные)
#defineUART1_RECEIVE(данные) UART_RECEIVE(1,данные)
[url=] [/url]
[url=] [/url]
/***********************************************************
Управление питанием и тактовыми частотами
***********************************************************/
//Получите кроссовер с часами
#defineCLKSPD (CLKCON и 0x07)
//Установите режим питания
#defineSET_POWER_MODE(режим)
делать{
если(режим ==0) { SLEEP &= ~0x03; }
Другое если(режим ==3) { SLEEP |=0x03; }
Другое{ SLEEP &= ~0x03; SLEEP |= режим; }
PCON |=0x01;
asm("NOP");
}в то время как (0)
//Режим параметров устанавливается на следующие значения:
#definePOWER_MODE_0 0x00
#definePOWER_MODE_1 0x01
#definePOWER_MODE_2 0x02
#definePOWER_MODE_3 0x03
//Используется для обнаружения устойчивости высокочастотных RC-осцилляторов
#defineHIGH_FREQUENCY_RC_OSC_STABLE (СОН и 0x20)
//Используется для обнаружения стабильного состояния кристаллического осциллятора
#defineXOSC_STABLE (СОН и 0x40)
//Получите значение частоты тика таймера
#defineTICKSPD ((CLKCON и 0x38) >> 3)
//Установите главную тактовую частоту
#defineSET_MAIN_CLOCK_SOURCE(источник)
делать{
если(источник) {
CLKCON |=0x40;
в то время как(! HIGH_FREQUENCY_RC_OSC_STABLE);
если(TICKSPD ==0){
CLKCON |=0x08;
}
СОН |=0x04;
}
Другое{
SLEEP &= ~0x04;
в то время как(! XOSC_STABLE);
asm("NOP");
CLKCON &= ~0x47;
СОН |=0x04;
}
}в то время как (0)
//Значение источника параметров равно:
#defineКРИСТАЛ 0x00 //Кристаллический осциллятор
#defineRC 0x01 //RC-осциллятор
[url=] [/url]
[url=] [/url]
/***********************************************************
Таймер 1
***********************************************************/
//Таймер 1 позволяет прервать переполнение счёта
#defineTIMER1_ENABLE_OVERFLOW_INT(Вал)
(TIMIF = (вал) ? TIMIF |0x40: TIMIF & ~0x40)
//Установите флаг прерывания переполнения для таймера 1
#defineTIMER1_OVERFLOW_INT_SETFLAG(f) (T1CTL= ((T1CTL & (~0x10)) | f))
//Таймер 1 запускается
#defineTIMER1_RUN(значение) (T1CTL = (значение)? T1CTL|0x02 : T1CTL&~0x03)
//Установите деление часов для таймера
#defineSET_TIMER_TICK(value) do{ CLKCON = ((CLKCON & (~0x38)) | value); } while(0)
//Значение значения равно:
#defineTIMER1_TICK_32M 0x00 //32 МГц
#defineTIMER1_TICK_16M 0x08 //16 МГц — значение по умолчанию для сброса системы
#defineTIMER1_TICK_8M 0x10 //8 МГц
#defineTIMER1_TICK_4M 0x18 //4МГц
#defineTIMER1_TICK_2M 0x20 //2МГц
#defineTIMER1_TICK_1M 0x28 //1МГц
#defineTIMER1_TICK_500k 0x30 //500 кГц
#defineTIMER1_TICK_250k 0x38 //250 кГц
//Установите кроссовер TICK на таймер 1
#defineSET_TIMER1_TICKDIV(значение)
делать{
T1CTL &= ~0x0c;
T1CTL |= значение;
}в то время как (0)
//где значение равно:
#defineTIMER1_TICKDIV_1 0x00 //1 дивизион
#defineTIMER1_TICKDIV_8 0x04 //8-каналная частота
#defineTIMER1_TICKDIV_32 0x08
#defineTIMER1_TICKDIV_128 0x0c
//Установите период переполнения таймера
#defineSET_TIMER1_PERIOD(значение)
делать{
T1CC0H = HIGH_BYTE(значение);
T1CC0L = LOW_BYTE(значение);
}в то время как (0)
//Установите режим работы таймера 1
#defineSET_TIMER1_MODE(режим)
делать{
T1CTL = ((T1CTL & (~0x03)) | режим);
}в то время как (0)
//Значение режима равно:
#defineTIMER1_MODE_STOP 0x00
#defineTIMER1_MODE_FREE 0x01
#defineTIMER1_MODE_MODULE 0x02
#defineTIMER1_MODE_UPDOWN 0x03
[url=] [/url]
[url=] [/url]
/***********************************************************
Сторожевой пёс
***********************************************************/
//Установите период переполнения для таймера watchdog
#defineWDT_SET_TIMEOUT_PERIOD(тайм-аут)
делать{ WDCTL &= ~0x03; WDCTL |= тайм-аут; }в то время как (0)
//Значение тайм-аута параметра равно:
#defineSEC_1 0x00 //после 1 секунды
#defineM_SEC_250 0x01 //После 250 мс
#defineM_SEC_15 0x02 //После 15 мс
#defineM_SEC_2 0x03 //После 2 мс
//Процедуры кормления собак
#defineWDT_RESET() do {
WDCTL = (WDCTL & ~0xF0) |0xA0;
WDCTL = (WDCTL & ~0xF0) |0x50;
} в то время как (0)
//Запустить/остановить таймер watchdog
#defineWDT_ENABLE() WDCTL |= 0x08
#defineWDT_DISABLE() WDCTL &= ~0x08
[url=] [/url]
[url=] [/url]
/***********************************************************
ADC
***********************************************************/
//Настройте один АЦП
#defineADC_SINGLE_CONVERSION(настройки)
делать{ ADCCON3 = настройки; }в то время как(0)
//Настройка параметров состоит из следующих комбинаций:
//Опорное напряжение
#defineADC_REF_1_25_V 0x00 //Внутреннее опорное напряжение 1,25 В
#defineADC_REF_P0_7 0x40 //Внешнее опорное напряжение на выводе AIN7
#defineADC_REF_AVDD 0x80 //AVDD_SOC Значки
#defineADC_REF_P0_6_P0_7 0xC0 //AIN6-AIN7 Внешнее опорное напряжение для дифференциальных входов
//Частота дискретизации
#defineADC_8_BIT 0x00 //8-е место
#defineADC_10_BIT 0x10 //10-е место
#defineADC_12_BIT 0x20 //12-е место
#defineADC_14_BIT 0x30 //14-е место
//Входите в канал
#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 //Земля
#defineADC_TEMP_SENS 0x0E //Встроенный датчик температуры
#defineADC_VDD_3 0x0F //VDD/3
Конвертация АЦП завершена
#define ADC_SAMPLE_READY() (ADCCON1 и 0x80)
#endif
//启动ADC转化
#define ADC_START()
do { ADCCON1 |= 0x40; } в то время как (0)//Выберите режим триггера АЦП как ручной (то есть ADC_SAMPLE_READY)
#defineADC_STOP()
делать{ ADCCON1 |=0x30; }в то время как (0)[url=] [/url]
(2) Функциональный модульный слой
[url=] [/url]
/***********************************************************
*Имя файла: module.h
*Автор: hustlzp
*Дата: 6 марта 2011 года
*Версия: 1.0
*Описание функции: Файл заголовка слоя функционального модуля
*Список функций: void led_init()
пустоты timer1_init()
пустота uart0_init(пустота);
void Uart0SendString(неподписанный символ *s);
Float adc_start(пустота)
void get_temperature(неподписанный символ *выход, поплавок temp);
пустота watchdog_init(пустота);
*Изменённые записи:
***********************************************************/
#ifndef MODULE_H
#defineMODULE_H
#include"hal.h"
/***********************************************************
LED
***********************************************************/
//Определите светодиодные контакты
#defineled1 P1_0
#defineLED2 P1_1
#defineled3 P1_2
#defineled4 P1_3
//Светодиодный свет и выключение
#defineLED_OFF 1
#defineLED_ON 0
//Инициализация светодиодов
пустотаled_init(пустота);
/***********************************************************
таймер1
***********************************************************/
//Используется для установки значения периода переполнения таймера
#defineTIMER1_OVF_2SEC 0xF424 //2s
#defineTIMER1_OVF_1SEC 0x7A12 //1s
#defineTIMER1_OVF_dot5SEC 0x3D09 //0,5 с
//Таймер 1 инициализируется
пустота timer1_init(пустота);
/***********************************************************
UART0
***********************************************************/
//Инициализация UART0
пустота uart0_init(пустота);
//Строка передачи последовательных портов
пустота Uart0SendString(без знакаЧар*s);
/***********************************************************
ADC-14
***********************************************************/
//Используется для преобразования данных, полученных АЦП, в температуру Цельсия
#defineADC_TO_CELSIUS(temp) (temp * 0.06229 - 311.43)
//Инициировать конверсию АЦП
Платформаadc_start(пустота);
//Переоборудование
пустота get_temperature(без подписи)Чар*выход,Платформавременная);
/***********************************************************
WatchDog
***********************************************************/
//Инициализация сторожевой собаки
пустота watchdog_init(пустота);
#endif
[url=] [/url]
[url=] [/url]
/***********************************************************
*Имя файла: module.c
*Автор: hustlzp
*Дата: 2011/3/11
*Версия: 1.0
*Описание функции: исходный файл уровня функционального модуля
*Список функций: (опущено)
*Изменённые записи:
***********************************************************/
#include"module.h"
/***********************************************************
*Название функции: led_init
*Функция функции: инициализация светодиодов
*Параметры входа: отсутствуют
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаled_init(пустота)
{
//Настройте P1.0, P1.1, P1.2 и P1.3 как общие порты ввода/вывода
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;
}
/***********************************************************
*Название функции: timer1_init
* Функция функции: инициализация таймера 1
*Параметры входа: отсутствуют
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаtimer1_init(пустота)
{
INT_GLOBAL_ENABLE(INT_ON); //Открыть глобальное прерывание
INT_ENABLE(INUM_T1, INT_ON); //Открытое прерывание T1
TIMER1_ENABLE_OVERFLOW_INT(INT_ON); //Прерывание переполнения отсчёта T1
SET_TIMER_TICK(TIMER1_TICK_4M); //Установите таймер TICK на 4 МГц
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC); //Установите период отсчёта от T1 до 2 секунд
SET_TIMER1_TICKDIV(TIMER1_TICKDIV_128); //Установите кроссовер часов с T1 на 128
SET_TIMER1_MODE(TIMER1_MODE_MODULE); //Установите режим работы T1 на модуль
}
/***********************************************************
*Название функции: uart0_init
*Функция: инициализация последовательного порта UART0
*Параметры входа: отсутствуют
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаuart0_init(пустота)
{
//Выберите местоположение UART
IO_PER_LOC_UART0_AT_PORT0_PIN2345();
//Настройка UART: разрешено приём, 115200 bps, однобитный стоп-бит, без паритета
UART_SETUP(0, UART_RECEIVE_ENABLE,115200, ONE_STOP_BITS | PARITY_DISABLE);
//Откройте полное прерывание
INT_GLOBAL_ENABLE(INT_ON);
//Открыть последовательный порт 0 для приема прерываний
INT_ENABLE(INUM_URX0, INT_ON);
}
/***********************************************************
*Имя функции: Uart0SendString
* Функция функции: инициализация таймера 1
*Параметр ввода: неподписанный символ *s
Верёвка, которую ты хочешь отправить
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаUart0SendString(без знакаЧар*s)
{
в то время как(*s !=0)
UART0_SEND(*s++);
}
/***********************************************************
*Название функции: adc_start
*Функция функции: Начало преобразования АЦП
*Параметры входа: отсутствуют
*Параметр экспорта: float
Значение температуры на планшете
***********************************************************/
Платформаadc_start(пустота)
{
Без подписанияintвременный;
//Опорное напряжение — 1,25 В, точность дискретизации — 14 бит, а цель преобразования — датчик температуры на чипе
ADC_SINGLE_CONVERSION(ADC_REF_1_25_V | ADC_14_BIT | ADC_TEMP_SENS);
ADC_STOP(); //Установите метод триггера для конвертации АЦП в ручное
ADC_START(); //Инициировать конверсию АЦП
в то время как(! ADC_SAMPLE_READY()); //Ждите завершения конвертации
temp = ADCL >>2; //Сохранить результаты преобразования в температуре
temp |= (((без знакаint) ADCH) <<6);
ВозвращениеADC_TO_CELSIUS(временная); //Возвращает фактическое значение температуры после преобразования
}
/***********************************************************
*Название функции: get_temperature
*Функция: Обработать значение температуры и сохранить его в массиве символов для последовательного вывода
*Параметр ввода: неподписанный символ *вывод
Используется для хранения преобразованного значения температуры
Температура поплавка
Значение температуры Цельсия
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаget_temperature(без подписи)Чар*выход,Платформавременно)
{
Выход[0] = (без знаковЧар)(временно) /10 + 48; //Десять мест
Выход[1] = (без знаковЧар)(temp) %10 + 48; //Однозначная цифра
Выход[2] ='.'; //Десятичная точка
Выход[3] = (без знаковЧар)(temp*10) %10 + 48; //Десятое
Выход[4] = (без знаковЧар)(temp*100) %10 + 48; //Процентиль
Выход[5] =''; //Эндификаторы струн
}
/***********************************************************
*Название функции: watchdog_init
*Функция функции: инициализация сторожевой собаки
*Параметры входа: отсутствуют
*Параметры экспорта: отсутствуют
***********************************************************/
пустотаwatchdog_init(пустота)
{
WDT_SET_TIMEOUT_PERIOD(SEC_1); //Установите время тайм-аута на 1 секунды
WDT_ENABLE(); //Запусти сторожевого пса
}
[url=] [/url]
(3) Прикладной уровень
[url=] [/url]
/*******************************************************************
Имя файла: main.c
Автор: hustlzp
Дата: 2011/3/11
Версия: 1.0
Описание функции: Основной файл программы
Список функций: (опущено)
Запись модификаций:
*******************************************************************/
#include
/********************************************************************
Процедуры прерывания сервиса
********************************************************************/
/* 定时器1溢出中断子程序
-------------------------------------------------------*/
#pragma вектор=T1_VECTOR
__interrupt пустота T1_ISR(пустота)
{
EA=0; Ворота прерываются
led2 = LED_ON;
get_temperature(выход,adc_start()); Преобразуем значение температуры в массив символов, которые нужно выводить
Uart0SendString(выход); Значение выходной температуры
Uart0SendString("°C");
LED2
/* 串口接收中断子程序
-------------------------------------------------------*/
#pragma вектор=URX0_VECTOR
__interrupt пустота RE_ISR(пустота)
{
EA=0;
led3 = LED_ON;
receive = U0DBUF;
if(type==1) // type=1, что указывает на то, что полученный символ используется для установки периода переполнения таймера
{
type=0;
Переключать(принимать)
{
случай '0': // Период переполнения таймера — 0,5 с
{
SET_TIMER1_PERIOD(TIMER1_OVF_dot5SEC);
перерыв;
}
случай '1': // Период переполнения таймера — 1с
{
SET_TIMER1_PERIOD(TIMER1_OVF_1SEC);
перерыв;
}
случай '2': // Период переполнения таймера — 2 секунды
{
SET_TIMER1_PERIOD(TIMER1_OVF_2SEC);
перерыв;
}
}
}
else if(type==2) // type=2, что указывает на то, что полученные символы используются для контроля сна
{
type=0;
led1 = LED_OFF;
led2 = LED_OFF;
led3 = LED_OFF;
Переключать(принимать)
{
случай '1': // Введите режим питания PM1
{
SET_POWER_MODE(1);
перерыв;
}
случай '2': // Введите режим питания PM2
{
SET_POWER_MODE(2);
перерыв;
}
случай '3': //Вход в режим питания PM3
{
SET_POWER_MODE(3);
перерыв;
}
}
}
else if(type==0) // type=0, что указывает, что полученный символ — это тип команды управления: @ или $
{
if(получить=='@')
{
type=1; Получается '@', чтобы указать, что следующий символ используется для установки периода переполнения
}
иначе if(receive=='$')
{
type=2; Получается '$', что означает, что следующий символ используется для управления системным сном
}
}
led3 = LED_OFF;
EA=1;
}
=LED_OFF;
TIMER1_OVERFLOW_INT_SETFLAG(INT_CLR); Очистите знак прерывания
EA=1; Открытое прерывание
}
/* 主函数
-------------------------------------------------------*/
Void main(void)
{
SET_MAIN_CLOCK_SOURCE(КРИСТАЛ); Установите системный тактовый сигнал на кристаллический осциллятор 32 МГц
led_init(); Инициализация светодиодов
uart0_init(); Инициализация последовательного порта UART0
timer1_init(); Таймер 1 инициализируется
watchdog_init(); Инициализация сторожевой собаки
в то время(1)
{
WDT_RESET(); Кормите собаку постоянно
}
}/********************************************************************
Основная программа
********************************************************************/
/* 全局变量
-------------------------------------------------------*/
неподписанный символ[6]={0}; Данные о температуре хранятся для удобства последовательного вывода
Неподписанные символы принимают; Храните полученных символов
незнаковый тип символа = 0; Флаг типа полученного символа устанавливается на 0/1/2"module.h"[url=] [/url]
5. ТестированиеОх~ Код наконец-то вставлен, это действительно утомительно, давайте протестируем эту небольшую систему:
(1) Временная дискретизация
Откройте последовательный порт и начинайте отладку IAR, и обнаруживайте, что LED1 включён, а значение температуры на инструменте последовательного порта постоянно генерируется, а интервал дискретизации определяется как 2 секунды:
(2) Контроль интервалов дискретизации
Введите «@1» в инструменте последовательного порта, затем проверьте интервал дискретизации и увидите, что он стал единицами; Появляется «@0», и интервал дискретизации меняется на 0,5 секунды.
(3) Контроль сна
Введите «$1» в инструменте последовательного порта, и все светодиоды выключены, а температурная дискретизация остановлена:
После тестирования система работает нормально и стабильно, и в целом соответствует требованиям.
Студенты, которым нужен исходный кодНажмите здесь, чтобы скачать
6. ЗаключениеВ этой статье приводится немного комплексный эксперимент в качестве примера, показывающий, как интегрировать встроенные ресурсы CC2430 для создания относительно стандартизированной небольшой системы. Через несколько дней я найду время написать простое руководство пользователя для hal.h, чтобы я и все могли легко управлять CC2430.
Далее я завершаю исследование ресурсов на чипе CC2430 и посвятлю себя изучению стека протокола TI Z-Stack~
Написание блога в этой серии на данный момент завершилось, но путь Зигби продолжится. Пейзажи впереди неизвестны, но я верю, что автор преодолеет препятствия вместе со всеми, почувствует взлёты и падения, и будут успехи.
Следите за новостями: блог-посты «Присоединяйтесь к TI Z-Stack»!