Всем привет.
Делаю я тут проект радиотермометра на attiny2313. Вроде всё готово, всё работало, но что-то жрал передатчик много. Батарейки долго не проживут.
Решил ввести режим сна. С просыпанием через ватчдог, каждую секунду, и с отсылкой температуры на каждой девятисотой секунде (раз в 15 минут). И ничего не работает
. Отсылает температуру после пробуждения, и..засыпает мертвым сном. Больше не просыпается.
Укажите на ошибку, пожалуйста!
Делаю я тут проект радиотермометра на attiny2313. Вроде всё готово, всё работало, но что-то жрал передатчик много. Батарейки долго не проживут.
Решил ввести режим сна. С просыпанием через ватчдог, каждую секунду, и с отсылкой температуры на каждой девятисотой секунде (раз в 15 минут). И ничего не работает
Укажите на ошибку, пожалуйста!
Спойлер
Код: Выделить всё
#define F_CPU 8000000UL // Тактовая частота микроконтроллера 8 МГц
// Подключаю стандартные библиотеки
#include <avr/io.h> // Ножки ввода-вывода
#include <avr/wdt.h> // здесь организована работа с ватчдогом
#include <avr/sleep.h> // здесь описаны режимы сна
#include <avr/interrupt.h> // работа с прерываниями
#include <util/delay.h> // Задержки
#include <stdlib.h>
// Датчик DS18B20 - любая свободная ножка МК
#define DS18B20 5
#define DS18B20_PORT PORTD
#define DS18B20_PIN PIND
#define DS18B20_DDR DDRD
uint8_t DS_scratchpad[9] = {0,0,0,0,0,0,0,0,0}; // 9 байт, считанных с DS18B20, или так называемый "блокнот"
uint8_t Presense_errors = 0; // Счётчик ошибок - инициализация DS18B20
uint8_t Short_circuit_errors = 0; // Счётчик ошибок - КЗ линии данных DS18B20
int8_t Temperature = 0; // Температура преобразованная (целая часть градусов)
#define DELAY 50000 // настройка скорости (частоты)
#define WAIT_DELAY 5
#define RF_PORT PORTD // порт передачи
#define RF_PIN PIND // порт чтения
#define RF_DDR DDRD
#define OUT_PIN 6 // линия передачи
#define IN_PIN 0 // линия чтения
#define SET(r, b) (r |= (1 << b)) // установка бита порта
#define CLR(r, b) (r &= ~(1 << b)) // сброс бита порта
#define OUT_LOW (CLR(RF_PORT, OUT_PIN)) // низкий уровень CE
#define OUT_HIGH (SET(RF_PORT, OUT_PIN)) // высокий уровень CE
#define BIT(p,b) (b)
#define PORT(p,b) (PORT ## p)
#define PIN(p,b) (PIN ## p)
#define DDR(p,b) (DDR ## p)
#define Set_Port_Bit(p,b) ((p) |= _BV(b))
#define Clr_Port_Bit(p,b) ((p) &= ~_BV(b))
#define Tgl_Port_Bit(p,b) ((p) ^= _BV(b))
#define Get_Port_Bit(p,b) (((p) & _BV(b)) != 0)
//user functions:
#define bit(io) BIT(io)
#define port(io) PORT(io)
#define pin_high(io) Set_Port_Bit(PORT(io),BIT(io))
#define pin_low(io) Clr_Port_Bit(PORT(io),BIT(io))
#define pin_toggle(io) Tgl_Port_Bit(PORT(io),BIT(io))
#define get_output(io) Get_Port_Bit(PORT(io),BIT(io))
#define get_input(io) Get_Port_Bit(PIN(io),BIT(io))
#define set_dir_in(io) Clr_Port_Bit(DDR(io),BIT(io))
#define set_dir_out(io) Set_Port_Bit(DDR(io),BIT(io))
#define dir_toggle(io) Tgl_Port_Bit(DDR(io),BIT(io))
#define LED_POWER D,PD1
#define LED_START D,PD4
#define LED_DATA D,PD3
#define LED_CRC D,PD2
typedef struct {
unsigned char start;
unsigned char temp;
unsigned char control_code;
} RFpacket;
// Инициализирую DS18B20
void DS18B20_init (void)
{
if ((DS18B20_PIN & (1 << DS18B20)) == 0) Short_circuit_errors++; // Проверяю КЗ линии данных
DS18B20_PORT &= ~(1 << DS18B20); // Устанавливаю низкий уровень
DS18B20_DDR |= (1 << DS18B20);
_delay_us(490);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(68);
if ((DS18B20_PIN & (1 << DS18B20)) > 0) Presense_errors++; // Ловлю импульс присутствия датчика
// Если датчик не подключен, Presense_errors увеличиваю на 1
_delay_us(422);
}
// Функция чтения байта из DS18B20
uint8_t DS18B20_read (void)
{
uint8_t dat = 0;
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(4);
dat = dat >> 1;
if (DS18B20_PIN & (1 << DS18B20))
{
dat |= 0x80;
}
_delay_us(62);
}
return dat;
}
// Функция чтения "блокнота" из DS18B20
void DS18B20_read_scratchpad (void)
{
for (uint8_t i=0; i<9; i++) // Считываю 9 байт данных, или так называемый "блокнот"
{
DS_scratchpad[i] = DS18B20_read();
}
}
// Функция записи байта в DS18B20
void DS18B20_write (uint8_t dat)
{
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
if (dat & 0x01)
{
DS18B20_DDR &= ~(1 << DS18B20);
}
else
{
DS18B20_DDR |= (1 << DS18B20);
}
dat = dat >> 1;
_delay_us(62);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(2);
}
}
// Алгоритм для вычисления CRC-8 для DALLAS.
// Для первого байта CRC = 0, для остальных - то, что получилось от предыдущего.
// В расчёт CRC входят первые 8 байт DS18B20.
// 1. Нахождение логического исключающего ИЛИ между младшим битом CRC и младшим битом данных.
// 2. Если результат равен 0, то:
// - Сдвиг вправо CRC.
// 3. Если результат равен 1, то:
// - Поиск нового значения CRC путем вычисления логического исключающего ИЛИ между CRC и полиномом CRC.
// - Сдвиг вправо CRC.
// - Установка старшего бита CRC в 1.
// - Сдвиг вправо данных.
// - Повтор данной последовательности 8 раз на 1 байт данных.
uint8_t DS18B20_crc (uint16_t adress)
{
uint8_t crc = 0; // Переменная для накопления CRC
for (uint8_t i=0; i<8; i++) // Считаю CRC 8-ми байт, 9-й байт это CRC
{
// Расчитываю CRC одного байта
crc = crc ^ (*(uint16_t*)(adress+i));
for (uint8_t j=0; j<8; j++)
{
if (crc & 0x01) crc = (crc >> 1) ^ 0x8C;
else crc >>= 1;
}
}
return crc; // Возвращаю CRC
}
unsigned char CC_my(int temp, int start){//ControlCode_my
unsigned char val = temp;
for (uint8_t i=0; i<8; i++){
val=val^start;
val=val >> 1;
}
return (unsigned char)val;
}
void RF_init()
{
/*настройка входа и выхода*/
RF_DDR = (1<<OUT_PIN)|(0<<IN_PIN);
RF_PORT = (1<<OUT_PIN)|(1<<IN_PIN);
set_dir_out(LED_POWER);
set_dir_out(LED_START);
set_dir_out(LED_DATA);
set_dir_out(LED_CRC);
}
// передача байта
void RF_write(unsigned char data){
unsigned char i;
for(i = 0; i < 8; i++){ // передача данных
if(((data >> 7) & 1)) { // получение одного бита для передачи
OUT_HIGH; // передача единицы
} else {
OUT_LOW; // передача нуля
}
_delay_us(DELAY);
data <<= 1;
}
}
void transmit(RFpacket rfp){
for (uint8_t i=0; i<100; i++){
pin_high(LED_START);
RF_write(rfp.start);
pin_low(LED_START);
OUT_LOW;
_delay_ms(WAIT_DELAY);
pin_high(LED_DATA);
RF_write(rfp.temp);
pin_low(LED_DATA);
OUT_LOW;
_delay_ms(WAIT_DELAY);
pin_high(LED_CRC);
RF_write(rfp.control_code);
pin_low(LED_CRC);
OUT_LOW;
_delay_ms(WAIT_DELAY);
}
}
volatile int count=900; // начинаем сразу с нужного значения, для того чтоб со старта отправить
//#define debug //раскомментить для протеуса
// в протеусе работат только Idle, в реальном же железе будем использовать PWR Down
#ifdef debug
#define sleep() OUT_LOW;\
set_sleep_mode(SLEEP_MODE_IDLE);\
sleep_mode();
#else
#define sleep() OUT_LOW;\
set_sleep_mode(SLEEP_MODE_PWR_DOWN);\
sleep_mode();
#endif
ISR (WDT_OVERFLOW_vect) {
wdt_reset(); // reset watchdog timer
WDTCR = (1<<WDE) | (1<<WDCE); // enable watchdog
WDTCR = (1<<WDIE) | WDTO_1S; // watchdog interrupt instead of reset
count++;
}
int main (void)
{
RF_init();
wdt_reset(); // reset watchdog timer
WDTCR = (1<<WDE) | (1<<WDCE); // enable watchdog
WDTCR = (1<<WDIE) | WDTO_1S; // watchdog interrupt instead of reset
asm volatile ("sei"); // разрешаем прерывания глобально
while(1)
{
if(count==900){
count=0;
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0x44); // Запускаю температурное преобразование
_delay_ms(1000); // Жду окончания температурного преобразования
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0xBE); // Команда на чтение содержимого ОЗУ
DS18B20_read_scratchpad(); // Считываю "блокнот"
if (Short_circuit_errors | Presense_errors) // Если датчик не отвечает на Presense-импульс, либо КЗ линии данных
{
}
else
{
if (DS_scratchpad[8] == DS18B20_crc(&DS_scratchpad[0])) // Если принятая CRC совпала с расчётной CRC
{
pin_high(LED_POWER);
Temperature = (int8_t)((DS_scratchpad[1] << 4)|(DS_scratchpad[0] >> 4)); // Совмещаю младший и старший байты, отбрасываю дробную часть, получаю температуру в градусах.
RFpacket pck;
pck.temp=(unsigned char)Temperature;
pck.start=0b10101101;
pck.control_code=CC_my(pck.temp,pck.start);
transmit(pck);
}
else // Если принятая CRC не совпала с расчётной, ничего не делаем
{
}
}
Presense_errors=Short_circuit_errors=0; // Сбрасываю счётчик ошибок инициализации DS18B20, сбрасываю флаг КЗ
pin_low(LED_POWER);
}
wdt_reset(); // reset watchdog timer
MCUSR &= ~(1<<WDRF); // clear reset flag
WDTCR = (1<<WDE) | (1<<WDCE); // enable watchdog
WDTCR = (1<<WDIE) | WDTO_1S; // watchdog interrupt instead of reset
sleep();
}
}