ATtiny13A 101 применение

kolyn
Offline
Зарегистрирован: 18.01.2019

DetSimen пишет:

У мня уличный даччик на 85+SoftSerial+JDY40. Раз в минуту шлёт данные.  На компе я их ловлю, и на рабочий стол ложу.  Скорость 9600, стабильность - ну примерно один пакет из 20 приходит битый.

Спасибо. Еще вопрос вдогонку - как организовано питание? Напрямую от лития нельзя JDY40, хотя пишут опять разное.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Именно напрямую от лития. Я ее как-то по недосмотру и от 5В питал долгое время. Потом протрезвел, ужаснулся, переключил на 3.3В. Потом купил  lm2950 на 3.3, да ставить лень, так от лития и питается. Отключаю CS - ом, тогда она в сон падает и не жрет ничо

b707
Offline
Зарегистрирован: 26.05.2017

kolyn пишет:

Господа. Есть ли у кого реальный опыт использования ATtiny 13/45/85 + софтСериал + JDY-40?

у меня чуть другая связка - Тини85 + СофтСериал + HC-12. Трудится больше года, шлет данные датчика раз минуту. Питание от лития напрямую. Автономность 5 месяцев на батарейке емкостью 550мАч

satelit 2
Offline
Зарегистрирован: 04.12.2016

новую тему не стал создавать, решил написать здесь. на этом форуме нашел скетч копировальщика домофонных ключей. на ардуино работает, проверял. решил его реализовать на аттини 85. прошивал через usbasp. вывода проверял через блинк, все работают, да и мк новый. но почему то на тиньке работать не хочет

#include <OneWire.h>
//#include <Adafruit_GFX.h>
//#include <Adafruit_PCD8544.h>
#define pin 0
//#define contrast 52  // контрастность дисплея
//Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); 
OneWire ibutton (pin); // Пин D11 для подлючения iButton (Data)
byte addr[8];
byte ReadID[8] = { 0x01, 0xB7, 0x84, 0x33, 0x10, 0x00, 0x00, 0xE1 }; // "Универсальный" ключ. Прошивается последовательность 01:FF:FF:FF:FF:FF:FF:2F

const int buttonPin = 1;
const int ledPin = 2;
int buttonState = 0;
int writeflag = 0;
int readflag = 0;
int val = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
 // Serial.begin(115200);
  display.begin();
//display.setContrast(contrast);  
//display.clearDisplay();

}

void loop() {

  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    readflag = 1;
    writeflag = 1;
    digitalWrite(ledPin, HIGH);
    val++;
    if (val > 6) val = 6;
    //Serial.print(val);
    
    delay(500);
  }
  else {
    val = 0;
  }


  if (!ibutton.search (addr)) {
    ibutton.reset_search();
    delay(50);
    if (val <= 5) return;
    val = 0;
  }

  digitalWrite(ledPin, HIGH);
  delay(50);

  for (byte x = 0; x < 8; x++) {
    //Serial.print(addr[x], HEX);
   // display.setTextColor( BLACK,WHITE);
// display.setCursor( 0, 10); display.print(addr[x], HEX);
    if (readflag == 0) {
      ReadID[x] = (addr[x]);
    }
   // Serial.print(":");
  }

  byte crc; // Проверка контрольной суммы
  crc = ibutton.crc8(addr, 7);
  
  //Serial.print("CRC: ");
  




 
 //display.setCursor( 0, 10); display.println("ok");                        
 //  display.setTextColor( BLACK,WHITE);
 //display.setCursor( 0, 20); display.println(crc, HEX);
  //Serial.println(crc, HEX);
  digitalWrite(ledPin, LOW);  
    
    delay(50);  
    display.display(); // выводим все на экран
   // Serial.println("ok");
  if ((writeflag == 1) or (Serial.read() == 'w')) {
    ibutton.skip(); ibutton.reset(); ibutton.write(0x33);
   // Serial.print("  ID before write:");
    for (byte x = 0; x < 8; x++) {
     // Serial.print(' ');
     // Serial.print(ibutton.read(), HEX);
    }
    // send reset
    ibutton.skip();
    ibutton.reset();
    // send 0xD1
    ibutton.write(0xD1);
    // send logical 0
    digitalWrite(pin, LOW); pinMode(pin, OUTPUT); delayMicroseconds(60);
    pinMode(pin, INPUT); digitalWrite(pin, HIGH); delay(10);

  // Serial.print('\n');
   // Serial.print("  Writing iButton ID:\n    ");
    byte newID[8] = { (ReadID[0]), (ReadID[1]), (ReadID[2]), (ReadID[3]), (ReadID[4]), (ReadID[5]), (ReadID[6]), (ReadID[7]) };
    ibutton.skip();
    ibutton.reset();
    ibutton.write(0xD5);
    for (byte x = 0; x < 8; x++) {
      writeByte(newID[x]);
    //  Serial.print('*');
    }
    //Serial.print('\n');
    ibutton.reset();
    // send 0xD1
    ibutton.write(0xD1);
    //send logical 1
    digitalWrite(pin, LOW); pinMode(pin, OUTPUT); delayMicroseconds(10);
    pinMode(pin, INPUT); digitalWrite(pin, HIGH); delay(10);
    writeflag = 0;
    readflag = 0;
    digitalWrite(ledPin, LOW);
  }
}

int writeByte(byte data) {
  int data_bit;
  for (data_bit = 0; data_bit < 8; data_bit++) {
    if (data & 1) {
      digitalWrite(pin, LOW); pinMode(pin, OUTPUT);
      delayMicroseconds(60);
      pinMode(pin, INPUT); digitalWrite(pin, HIGH);
      delay(10);
    } else {
      digitalWrite(pin, LOW); pinMode(pin, OUTPUT);
      pinMode(pin, INPUT); digitalWrite(pin, HIGH);
      delay(10);
    }
    data = data >> 1;
  }
  return 0;
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

satelit 2 пишет:

новую тему не стал создавать, решил написать здесь. на этом форуме нашел скетч копировальщика домофонных ключей. на ардуино работает, проверял. решил его реализовать на аттини 85. прошивал через usbasp. вывода проверял через блинк, все работают, да и мк новый. но почему то на тиньке работать не хочет

#include <OneWire.h>
//#include <Adafruit_GFX.h>
//#include <Adafruit_PCD8544.h>
#define pin 0
//#define contrast 52  // контрастность дисплея
//Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); 
OneWire ibutton (pin); // Пин D11 для подлючения iButton (Data)
byte addr[8];
byte ReadID[8] = { 0x01, 0xB7, 0x84, 0x33, 0x10, 0x00, 0x00, 0xE1 }; // "Универсальный" ключ. Прошивается последовательность 01:FF:FF:FF:FF:FF:FF:2F

const int buttonPin = 1;
const int ledPin = 2;
int buttonState = 0;
int writeflag = 0;
int readflag = 0;
int val = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
 // Serial.begin(115200);
  display.begin();
//display.setContrast(contrast);  
//display.clearDisplay();

}

void loop() {

  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
    readflag = 1;
    writeflag = 1;
    digitalWrite(ledPin, HIGH);
    val++;
    if (val > 6) val = 6;
    //Serial.print(val);
    
    delay(500);
  }
  else {
    val = 0;
  }


  if (!ibutton.search (addr)) {
    ibutton.reset_search();
    delay(50);
    if (val <= 5) return;
    val = 0;
  }

  digitalWrite(ledPin, HIGH);
  delay(50);

  for (byte x = 0; x < 8; x++) {
    //Serial.print(addr[x], HEX);
   // display.setTextColor( BLACK,WHITE);
// display.setCursor( 0, 10); display.print(addr[x], HEX);
    if (readflag == 0) {
      ReadID[x] = (addr[x]);
    }
   // Serial.print(":");
  }

  byte crc; // Проверка контрольной суммы
  crc = ibutton.crc8(addr, 7);
  
  //Serial.print("CRC: ");
  




 
 //display.setCursor( 0, 10); display.println("ok");                        
 //  display.setTextColor( BLACK,WHITE);
 //display.setCursor( 0, 20); display.println(crc, HEX);
  //Serial.println(crc, HEX);
  digitalWrite(ledPin, LOW);  
    
    delay(50);  
    display.display(); // выводим все на экран
   // Serial.println("ok");
  if ((writeflag == 1) or (Serial.read() == 'w')) {
    ibutton.skip(); ibutton.reset(); ibutton.write(0x33);
   // Serial.print("  ID before write:");
    for (byte x = 0; x < 8; x++) {
     // Serial.print(' ');
     // Serial.print(ibutton.read(), HEX);
    }
    // send reset
    ibutton.skip();
    ibutton.reset();
    // send 0xD1
    ibutton.write(0xD1);
    // send logical 0
    digitalWrite(pin, LOW); pinMode(pin, OUTPUT); delayMicroseconds(60);
    pinMode(pin, INPUT); digitalWrite(pin, HIGH); delay(10);

  // Serial.print('\n');
   // Serial.print("  Writing iButton ID:\n    ");
    byte newID[8] = { (ReadID[0]), (ReadID[1]), (ReadID[2]), (ReadID[3]), (ReadID[4]), (ReadID[5]), (ReadID[6]), (ReadID[7]) };
    ibutton.skip();
    ibutton.reset();
    ibutton.write(0xD5);
    for (byte x = 0; x < 8; x++) {
      writeByte(newID[x]);
    //  Serial.print('*');
    }
    //Serial.print('\n');
    ibutton.reset();
    // send 0xD1
    ibutton.write(0xD1);
    //send logical 1
    digitalWrite(pin, LOW); pinMode(pin, OUTPUT); delayMicroseconds(10);
    pinMode(pin, INPUT); digitalWrite(pin, HIGH); delay(10);
    writeflag = 0;
    readflag = 0;
    digitalWrite(ledPin, LOW);
  }
}

int writeByte(byte data) {
  int data_bit;
  for (data_bit = 0; data_bit < 8; data_bit++) {
    if (data & 1) {
      digitalWrite(pin, LOW); pinMode(pin, OUTPUT);
      delayMicroseconds(60);
      pinMode(pin, INPUT); digitalWrite(pin, HIGH);
      delay(10);
    } else {
      digitalWrite(pin, LOW); pinMode(pin, OUTPUT);
      pinMode(pin, INPUT); digitalWrite(pin, HIGH);
      delay(10);
    }
    data = data >> 1;
  }
  return 0;
}

 

 

что-то с дисплеем накосячил

satelit 2
Offline
Зарегистрирован: 04.12.2016

я дисплей закоментировал, я его не использую. тупо кнопка, диод и контакты под ibutton

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

satelit 2 пишет:
я дисплей закоментировал, я его не использую. тупо кнопка, диод и контакты под ibutton

ДА НУ?

строка 22, 83  далее не смотрел )))

satelit 2
Offline
Зарегистрирован: 04.12.2016

было дело, компилятор ругался, все исправлено было. 

satelit 2
Offline
Зарегистрирован: 04.12.2016

может дело в таймерах? в прошлый раз мне подсказали таймер2 поменять на таймер0, но я так и не разобрался

Sok
Offline
Зарегистрирован: 05.01.2018

Подскажите как работать с EEPROM ATTyni13. Программирую через Ардуино всё время выдаёт ошибки

compilation terminated.

exit status 1
EEPROM.h: No such file or directory
 
вот человек делает https://www.youtube.com/watch?v=uKqQDFAI_Dk
а у меня в примерах когда выбираю Attyni13 нет пункта EEPROM 
Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Sok

1. ATTyni13 не существует !!!

2. Вы брали пакет поддержки Tiny там же где и автор видео ?

Вот тут под видео есть ссылки на пакет, который он использует -

https://www.youtube.com/watch?v=rzSS_lGbVpU&list=PLwj1S-y03QNhxqAKbr85ICK60GxnvVRx3

Sok
Offline
Зарегистрирован: 05.01.2018

Там ссылка на текстовый код! Как его поместить в библиотеку?

Sok
Offline
Зарегистрирован: 05.01.2018

Простите за опечатку

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Там ссылка json на модуль поддержки плат Tiny.

Sok
Offline
Зарегистрирован: 05.01.2018

Komandir пишет:

Там ссылка json на модуль поддержки плат Tiny.

Я наверно торможу, ткните пальцем, или скопируйте мне ссылку пожалуйста.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Цитата:

Я наверно торможу

Наверно.

Копируешь ссылку на json-файл в браузере. Потом заходишь в настройки Arduino IDE и вставляешь ссылку в строку "Дополнительные ссылки для менеджера плат".

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018
Sok
Offline
Зарегистрирован: 05.01.2018

Громадное спасибо!!! Я просто не сталкивался с таким способом установки библиотек....

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Игорь Я пишет:

Доброго дня (вечера) Всем!

Я тут появлялся года 2 назад с темой программирования Attiny13, спасибо помогли. 

Теперь новая загвоздка: на тини13 реализовать схему цикличного таймера на 24 часа.  На выводе Pin3 через сутки меняется уровень с 0 на 1 (уход +- 10 минут за сутки допускается). На выводе Pin4 уровень меняется с частотой 0,5Гц - для светодиода.

Код зашил в аттини. На малых режимах времени работает нормально, но при установке 12 часов переключение происходит с запаздыванием почти на 40-50 минут в течение суток. Я представляю какой будет разброс если введу 24 часа...

Местные Гуру, помогите советом!

   

Видимо так:

// Эти переменные хранят временной шаблон для интервалов мигания
// и текущее состояние светодиодов

int ledPin1 = 3; // номер пина со светодиодом
int ledState1 = LOW; // состояние светодиода
// последний момент времени, когда состояние светодиода изменялось
unsigned long previousMillis1 = 0;
long OnTime1 = 42408000; // длительность свечения светодиода (в миллисекундах)
long OffTime1 = 42408000; // светодиод не горит (в миллисекундах)

int ledPin2 = 4; // номер пина со светодиодом
int ledState2 = LOW; // состояние светодиода
// последний момент времени, когда состояние светодиода изменялось
unsigned long previousMillis2 = 0;
long OnTime2 = 500; // длительность свечения светодиода (в миллисекундах)
long OffTime2 = 500; // светодиод не горит (в миллисекундах)

void setup() {
  // устанавливаем цифровой пин со светодиодом как ВЫХОД
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop() {
  // выясняем не настал ли момент сменить состояние светодиода

  unsigned long currentMillis = millis(); // текущее время в миллисекундах

  // конечный автомат для 1-го светодиода
  if ((ledState1 == HIGH) && (currentMillis - previousMillis1 >= OnTime1))
  {
    ledState1 = LOW; // выключаем
    previousMillis1 = previousMillis1 +  OnTime1;
    //  previousMillis1 = currentMillis; // запоминаем момент времени
    digitalWrite(ledPin1, ledState1); // реализуем новое состояние
  }
  else if ((ledState1 == LOW) && (currentMillis - previousMillis1 >= OffTime1))
  {
    ledState1 = HIGH; // выключаем
    previousMillis1 = previousMillis1 +  OffTime1;
    // previousMillis1 = currentMillis ; // запоминаем момент времени
    digitalWrite(ledPin1, ledState1); // реализуем новое состояние
  }

  // конечный автомат для 2-го светодиода
  if ((ledState2 == HIGH) && (currentMillis - previousMillis2 >= OnTime2))
  {
    ledState2 = LOW; // выключаем
    previousMillis2 = previousMillis2 + OnTime2;
    //previousMillis2 = currentMillis; // запоминаем момент времени
    digitalWrite(ledPin2, ledState2); // реализуем новое состояние
  }
  else if ((ledState2 == LOW) && (currentMillis - previousMillis2 >= OffTime2))
  {
    ledState2 = HIGH; // выключаем
    previousMillis2 = previousMillis2 + OffTime2;
   // previousMillis2 = currentMillis ; // запоминаем момент времени
    digitalWrite(ledPin2, ledState2); // реализуем новое состояние
  }
}

 

mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Хоть я и не местный гуру, но попробую предположить, что тактовый генератор у тиньки не самый точный. Как вариант попробовать считать время не через millis, а напрямую встроенным таймером и установить максимальную частоту работы. Хотя не факт, что это поможет.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

mir0tv0rec пишет:
попробую предположить, что тактовый генератор у тиньки не самый точный.
Ровно то же самое можно сказать про "встроенный таймер"

b707
Offline
Зарегистрирован: 26.05.2017

mir0tv0rec пишет:
Как вариант попробовать считать время не через millis, а напрямую встроенным таймером .

а миллис как, по вашему, считается? - через встроенный таймер :)

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

З.Ы. Мне как автору темы, очень приятно видеть, что всё вот так разрослось, тема перешла порог в 1800 сообщений, и я очень рад, что я был на истоках этой движухи...

Творите, ATtiny13 замечательный инструмент в умелых руках, я на нём даже ваттметр разворачивал:
https://www.youtube.com/watch?v=oXgvUM9U2ng

Emilio
Offline
Зарегистрирован: 16.12.2021

Добрый вечер друзья! Нужна помощь по слиянию двух программ на аттины13. Здесь приемник 433мгц и простая мигалка светодиодом.Задумка такая,для снижения потребления приемника я назначил PB4 как выход 3.6В ,приемник будет питаться именно в момент мигания светодиода то есть будет обесточен 2 секунды потом включаться на 2 секунды. Весь мозг сломал не получается объеденить это дело. делей сильно тормозит по этому отказался от этого. По отдельности все прекрасно работает.

#define F_CPU        1200000UL // Clock speed 1.2 MHz (-Ulfuse:w:0x6A:m)
#define TRF_RX_PIN      PB0     // Receiver on Pin 0
#define TRF_DATA_SIZE   2     // Command size 2 bytes
#define TRF_TX_DISABLED         // Exclude transmitter code to preserve space
#define TX_VCC_PIN  PB4       // Контакт приемника
#define LED_1_PIN   PB3       // Pin definitions for 1 LED
#include "tinyrf.h"
#include <util/delay.h>
// LED pins control macro
#define init_led_pins() DDRB |= (1 << LED_1_PIN)
#define set_led_pin(pin, state) state ? PORTB |= (1 << pin) : PORTB &= ~(1 << pin)

int main(void)
{
  // Initialize timer and ports
  trf_init();
  init_led_pins();
  
  while (1)
  {
    // If a new command is available
    if (trf_has_received_data()) {
      
      // Get received data
      uint8_t data_buffer[TRF_DATA_SIZE];
      trf_get_received_data(data_buffer);
      
      // Check data integrity (second byte must have inverted value of the first)
      if (data_buffer[0] == (uint8_t)(~data_buffer[1])) {
        switch (data_buffer[0]) {
          case 11:
          set_led_pin(LED_1_PIN, 1);  // Turn on LED1
          
           _delay_ms (2500);
           set_led_pin(LED_1_PIN, 0);  // Turn off LED1
                   
        }
      }
      
      // Reset state to listen for new messages
      trf_reset_received();
    }
  }
}
======================================================================

const int ledPin = PB4;  // переменная с номером пина светодиода
const long ledInterval = 200; // интервал мигания светодиодом, мсек.

int ledState = LOW;  // начальное состояние светодиода
unsigned long previousMillis = 0;  // храним время предыдущего срабатывания светодиода

void setup() {
       pinMode(ledPin, OUTPUT);   // задаём пин PB4 как выход.
}

void loop() {
    
    // Мигание светодиодом:
    // время с момента включения Arduino, мсек:
    unsigned long currentMillis = millis(); 
    // Если время мигать пришло,
    if (currentMillis - previousMillis >= ledInterval) {
        previousMillis = currentMillis;  // то запоминаем текущее время
        if (ledState == LOW) {  // и инвертируем состояние светодиода
              ledState = HIGH;
        } else {
              ledState = LOW;
        }
        digitalWrite(ledPin, ledState); // переключаем состояние светодиода
    }
}

 

mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Доброго времени!

Есть вопросик, накидал код для управления фонарем. Вроде все работает, но имеется одно но - периодически фонарь зависает в режиме сна, причем хаотично, помогает только сброс. Может ли быть дело в коде, сам уже несколько раз перепроверил, ничего критичного вроде не обнаружил. Может глаз конечно "замылился", можете глянуть?

//#define F_CPU 9600000UL // для Arduino IDE можно не указывать (вибирается из списка в меню плат)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define false 0 // ложь
#define true 1  // истина

volatile uint8_t sss1 = 0;            // счетчик значений АЦП
volatile uint8_t lowBat = false;      // батарея разряжена
volatile uint8_t flgClick = false;    // флаг клика
volatile uint8_t beUnPress = false;   // флаг отпускания
volatile uint8_t switchLED = false;   // флаг переключения диодов
volatile uint8_t keyFalsePress = true;   // флаг нажатия кнопки

volatile uint16_t tCounter = 0;       // счетчик мкС
volatile uint16_t msCounter = 0;      // счетчик кратно - 10мС
volatile uint16_t msCounterNow = 0;   // счетчик кратно - 10мС текущий
volatile uint16_t voltVal = 0;        // переменная для накопления значений АЦП

uint8_t PWM_MODE_LED[4] = {255, 0, 128, 235};  // режимы PWM (0% - 255, 100% - 0, 50% - 128, 25% - 192)
uint8_t PWM_MODE_COB[4] = {255, 0, 128, 192};  // режимы PWM (0% - 255, 100% - 0, 50% - 128, 25% - 192)
uint8_t butPressTime = 0; // счетчик времени нажатия
uint8_t pwmMode = 0;      // режим работы PWM (0 - выкл, 1 - макс., 3 - мин.)

uint8_t flgPress = false;   // признак кнопка в нажатом состоянии
uint8_t LedMode = false;    // переключатель светодиодов
uint8_t flgLngPress = false;  // признак удержания кнопки



//****************************************************************
// мигаем основным светодиодом при низком заряде
//
void BlinkLed(){
  TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); // отключаем ШИМ COB
  TCCR0A |= (1 << COM0A1) | (1 << COM0A0);  // включаем ШИМ PB0
  for (uint8_t i = 0; i < 5  ; i++){
    for (uint8_t j = 127; j < 255  ; j++){
      _delay_ms(1);     // отладка
      OCR0A = j;
    }// end for  
    for (uint8_t j = 255; j > 127  ; j--){
      _delay_ms(1);     // отладка
      OCR0A = j;
    }// end for
  }// end for  
}// end BlinkLed()

// переходим в режим сна
//
void RunSleep(){
  LedMode = false;
  flgLngPress = false;    // сбрасываем флаги
  flgPress = false;       // сбрасываем флаги
  TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); // отключаем ШИМ LED
  TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); // отключаем ШИМ COB
  PORTB &= ~((1 << PB4) | (1 << PB1) | (1 << PB0));  // низкий уровень на портах
  ADCSRA &= ~(1 << ADEN);   // выключаем АЦП
  GIMSK |= (1 << PCIE);     // включаем прерывания по кнопке
  PCMSK |= (1 << PCINT2);   // PCINT2 для возращения в нормальный режим из сна
  MCUCR |= (1 << SE); // режим сна включен
  asm("sleep");   // уходим в сон
  asm("nop");     // пустой цикл (вроде после сна нужен)
}// end RunSleep()

// устанавливаем режим работы светодиодов
//
void Set_PWM() {
  switch (LedMode) {
    case 0:
      TCCR0A &= ~((1<<COM0B1) | (1<<COM0B0)); // отключаем ШИМ PB1
      OCR0A = PWM_MODE_LED[pwmMode];
      TCCR0A |= (1<<COM0A1) | (1<<COM0A0);    // включаем ШИМ PB0
    break;
    
    case 1:
      TCCR0A &= ~((1<<COM0A1) | (1<<COM0A0)); // отключаем ШИМ PB0
      OCR0B = PWM_MODE_COB[pwmMode];
      TCCR0A |= (1<<COM0B1) | (1<<COM0B0);    // включаем ШИМ PB1
    break;
  }// end switch
}// end Set_PWM()

// выходим из сна по изменению состояния кнопки (обработчик прерывания)
//
ISR(PCINT0_vect){
  if (!(PINB & (1 << PB2))) {  // если включились по отпусканию кнопки 
    beUnPress = true; // поднимаем флаг включения по отпусканию кнопки 
  }// end if
  MCUCR &= ~(1 << SE);    // режим сна выключен
  GIMSK &= ~(1 << PCIE);  // выключаем прерывания по пинам
  PCMSK = 0x00;           // выключаем прерывания по выводу кнопки
  PORTB |= (1 << PB4);  // открываем полевик, подтягиваем делитель в минусу
  lowBat = false;       // снимаем флаг низкого уровня АКБ
  switchLED = false;    // снимаем флаг переключение светодиодов
  keyFalsePress = true;       // поднимаем флаг случайного нажатия / помехи / дребезга
  msCounterNow = msCounter;   // запускаем счетчик после нажатия
  ADCSRA |= (1 << ADEN)|(1 << ADSC);  // включаем АЦП
}// ISR(INT0_vect)

// обработчик прерывания АЦП
//
ISR(ADC_vect){
  
  uint16_t voltValTmp = 1024;
  
  voltVal += ADCW;  // добавляем текущее значение АЦП
  sss1++; // инкрементируем счетчик
  
  if (sss1 > 9) { // если количество отсчетов АЦП больше 10
    voltValTmp = voltVal / (sss1);  // находим среднее арифметичсекое АЦП
    voltVal = 0;
    sss1 = 0;
  }// end if

  // если напряжение меньше 3В - поднимаем флаг
  if (voltValTmp < 665) lowBat = true;  // ~3V  
  else lowBat = false;
}// end ISR (ADC_vect)


// обработчик прерывания по переполнению 0 таймера
//
ISR(TIM0_OVF_vect){
  tCounter++;
  if (tCounter > 375) { // ~10ms
    tCounter = 0; // обнуляем счетчик
    msCounter++;  // счетчик 10мс
  }// end if
}// ISR (TIM0_OVF_vect)


int main(void){
  
  DDRB |= (1 << PB4) | (1 << PB1) | (1 << PB0);   // порты 0, 1, 4 на выход
  PORTB |= (1 << PB4);    // открываем полевик, подтягиваем делитель к минусу
  
  // Отключаем компаратор
  ACSR = 0x00;        // обнуляем регистр
  ACSR |= (1 << ACD); // выключаем компаратор
    
  // Инициализируем АЦП
  ADMUX |= (1 << REFS0) | (1 << MUX1) | (1 << MUX0);  // внутреннее опорное напряжение, выбран вход ADC3 (PB3)
  ADCSRA |= (1 << ADEN) | (1 << ADSC) | (1 << ADATE)  // АЦП включен, запуск преобразования, режим автоизмерения,
  | (1 << ADIE)                                       // прерывание по окончанию преобразования,
  | (1 << ADPS2) | (1 << ADPS1)| (1 << ADPS0);        // частота CLK/128
  ADCSRB = 0x00;  // режим автоизмерения: постоянно запущено
  DIDR0 |= (1 << ADC3D); // запрещаем цифровой вход на ноге аналогового входа
  
  // Режим Fast PWM, частота сигнала=F_CPU / делитель*256
  OCR0A = 255; // регистр сравнения (инвертированный сигнал ШИМ 0)
  OCR0B = 255; // регистр сравнения (инвертированный сигнал ШИМ 0)
  TCCR0A |= (1<<WGM00) | (1<<WGM01) |   // Режим Fast PWM, таймер считает до 255 и сбрасывается в 0
            (1<<COM0A1) | (1<<COM0A0) | // 0 при равенстве регистров TCNT0 и OCROA. 1 при переполнении (инвертированный ШИМ-сигнал)
            (1<<COM0B1) | (1<<COM0B0);  // 1 при равенстве регистров TCNT0 и OCROB. 0 при переполнении (неинвертированный ШИМ-сигнал)
  TCCR0B |= (1<<CS00);  // делитель 1 (ШИМ ~37кГц)
  TIMSK0 |= (1 << TOIE0); // вкл. прерывание по переполнению таймера
  
  
  // настройка режима сна
  
  MCUCR |= (1 << SM1);  // power-down mode
    
  sei();    // разрешаем глобально прерывания

  //RunSleep(); // уходим в сон (в зашитой прошивке нет)

  while(1) {

    // если кнопка нажата
    if ((PINB & (1 << PB2)) && !flgLngPress) {
      _delay_ms(25);      // время на дребезг
      if (PINB & (1 << PB2)) {  // если кнопка все еще нажата
        keyFalsePress = false;  // снимаем флаг случайного нажатия
        butPressTime++;             // начало отсчета времени нажатия кнопки
        if (butPressTime >= 45){    // ~1 сек (15мс *(55 + обработка команд))
          flgLngPress = true;
          flgPress = false;        // клик
          butPressTime = 0;       // обнуляем счетчик времени нажатия
        }// end if
        else{
          flgPress = true; // клик
        }// end else
      }// end if  
    }// end if
    
    // отпустили кнопку (клик)
    if (flgPress && !(PINB & (1 << PB2))){
      flgPress = false; // сбрасываем флаг нажатия
      butPressTime = 0; // обнуляем счетчик времени нажатия
      pwmMode++;  // инкрементируем режим PWM
      if (pwmMode > 3) pwmMode = 0; // сбрасываем режим PWM (у нас всего 4 режима: 0-3)
      Set_PWM();  // устанавливаем режим светодиода
      if (!pwmMode) RunSleep(); // если PWM выключен, уходим в сон
    }// end if


    // если длительное нажатие
    if (flgLngPress && !switchLED){
      LedMode = !LedMode;   // переключаем на другой светодиод
      pwmMode = 1;
      Set_PWM();  // устанавливаем режим светодиода
      switchLED = true;   // поднимаем флаг, что переключили светодиоды (защита от многократно срабатывания)
    }// end if


    // если отпустили после длительного нажатия
    if (flgLngPress && !(PINB & (1 << PB2))){
      switchLED = false;
      flgLngPress = false;
      flgPress = false; // сбрасываем флаг нажатия
    }// end if

    
    // защита от помехи / случайного нажатия
    // если нажатие было случайное или помеха, фонарь не включен и прошло больше 2с
    if (keyFalsePress && !pwmMode && ((msCounter - msCounterNow) > 200)){
      RunSleep(); // выключаемся (засыпаем)  
    }// end if
    
    // если аккумулятор разрядился
    if (lowBat){
      if (!beUnPress) BlinkLed();
      else beUnPress = false;
      pwmMode = 0;
      RunSleep();
    }// end if
        
       
  }// end while(1)
}// end main

 

Есть еще фонарь на 44 тиньке, код примерно такой же, тоже периодически зависает, примерно также.
Т.е. не выходит из сна.

Sok
Offline
Зарегистрирован: 05.01.2018

232 строчки кода на фонарь. Но мы лёгких путей не ищем, так держать...

Green
Offline
Зарегистрирован: 01.10.2015

Так и хочется сказать. Дядя, "ты ещё мал и глуп. И не видал больших ..." Не видал обычных фонарей!
В основном файле 315 строк, в основном хедере 380 и ещё 30(!) дополнительных файлов. Лень считать.
Обычный фонарь. Одна кнопка - один светодиод.

Upper
Offline
Зарегистрирован: 23.06.2020

mir0tv0rec пишет:

 ничего критичного вроде не обнаружил. Может глаз конечно "замылился", можете глянуть?

void RunSleep(){
  LedMode = false;
  flgLngPress = false;    // сбрасываем флаги
  flgPress = false;       // сбрасываем флаги
  TCCR0A &= ~((1 << COM0A1) | (1 << COM0A0)); // отключаем ШИМ LED
  TCCR0A &= ~((1 << COM0B1) | (1 << COM0B0)); // отключаем ШИМ COB
  PORTB &= ~((1 << PB4) | (1 << PB1) | (1 << PB0));  // низкий уровень на портах
  ADCSRA &= ~(1 << ADEN);   // выключаем АЦП
  GIMSK |= (1 << PCIE);     // включаем прерывания по кнопке
  PCMSK |= (1 << PCINT2);   // PCINT2 для возращения в нормальный режим из сна
  MCUCR |= (1 << SE); // режим сна включен
  asm("sleep");   // уходим в сон
  asm("nop");     // пустой цикл (вроде после сна нужен)
}// end RunSleep()

Может быть дело не в этом, но часто для исключения неопределенности, запрещают все прерывания перед началом установок для сна и разрешают последней командой перед sleep. 

Из описания

When using the SEI instruction to enable interrupts, the instruction following SEI will be executed before any pending interrupts, as shown in this example.
 
Assembly Code Example
sei ; set Global Interrupt Enable
sleep; enter sleep, waiting for interrupt
; note: will enter sleep before any pending
; interrupt(s)
mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Благодарю. Попробую так сделать - в даташнике не прочитал этого, видимо так внимательно читал...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:

Наконец то пришли правильные стабилизаторы с микроамперными токами потребления в покое,

10 мкА без нагрузки, 16 мкА в спящем режиме всей схемы.

Уличный термометр, каждые ~17 минут отправляющий данные, скетч:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/io.h>
#include <util/delay.h>     /* for _delay_us() */

#define periodusec 400 // mcs
#define DS_BIT         4 // pin 3
#define RC_BIT         3 // pin 2

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// PB0 pin 5
#define PB0_OUT sbi(DDRB,PB0)
#define PB0_LOW cbi(PORTB,PB0)
// PB1 pin 6 - EN pin RFunit WL118
#define PB1_OUT sbi(DDRB,PB1)
#define PB1_HIGH sbi(PORTB,PB1)
#define PB1_LOW cbi(PORTB,PB1)
// PB2 pin 7
#define PB2_OUT sbi(DDRB,PB2)
#define PB2_LOW cbi(PORTB,PB2)
// PB3 pin 2
#define PB3_OUT sbi(DDRB,PB3);
#define PB3_LOW cbi(PORTB,PB3);
// PB4 pin 3
#define PB4_OUT sbi(DDRB,PB4)
#define PB4_IN cbi(DDRB,PB4)
#define PB4_HIGH sbi(PORTB,PB4)
#define PB4_LOW cbi(PORTB,PB4)

#define TimerCountSec 1027 // ~17min delay start by sec
word CurrentTime = 0;

void ExecFunc() {
  // установка режима для ds
  DDRB |= _BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  DDRB &= ~_BV(DS_BIT);
  // get temp and send
  PB1_OUT; PB1_HIGH; // ON RF unit
  word TReading = GetTemp();
  sendRC((unsigned long)(TReading + (word)11500)); // отправляем данные
  // OFF pins
  OneWireReset();
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
}

void CalcTimer() {
  ++CurrentTime;
  if (((CurrentTime + 1UL) * 8UL) >= TimerCountSec) {
    CurrentTime = 0;
    ExecFunc();
  }
}

ISR (WDT_vect)
{
  wdt_disable();  // disable watchdog
}

void setup () {
  // OFF pins
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
  unsigned long delp = millis(); while ((millis() - delp) <= 1000); // pause for enable all device and get temp to clock
  // first run
  ExecFunc();
  delp = millis(); while ((millis() - delp) <= 4000); // pause for enable all device and get temp to clock
  // second run
  ExecFunc(); // for exactly get temp
}

void loop ()
{
  CalcTimer();
  cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF
  setup_watchdog(9);
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts (); // timed sequence follows
  sleep_enable();
  sleep_bod_disable();
  interrupts ();  // guarantees next instruction executed
  sleep_cpu ();  // cancel sleep as a precaution
  sleep_disable();
}


// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
  byte bb; int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE); ww = bb;
  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCR |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCR = bb; WDTCR |= _BV(WDIE);
}


void sendRC(unsigned long data) { // Отправка данных по радиоканалу RCswitch. Двоичный протокол
  DDRB |= _BV(RC_BIT);
  data |= 3L << 20; // ?
  unsigned short repeats = 1 << (((unsigned long)data >> 20) & 7);
  data = data & 0xfffff;
  unsigned long dataBase4 = 0; uint8_t i;
  for (i = 0; i < 20; i++) {
    dataBase4 <<= 1;
    dataBase4 |= (data % 2);
    data /= 2;
  }
  unsigned short int j;
  for (j = 0; j < repeats; j++) {
    data = dataBase4; uint8_t i;
    for (i = 0; i < 20; i++) {
      switch (data & 1) {
        case 0:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec * 3);
          break;
        case 1:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec * 3);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec);
          break;
      }
      data >>= 1;
    }
    PORTB |= _BV(RC_BIT);
    _delay_us(periodusec);
    PORTB &= ~_BV(RC_BIT);
    _delay_us(periodusec * 31);
  }
}

// OneWire функции:

void OneWireReset()
{
  PORTB &= ~_BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_us(500);
  DDRB &= ~_BV(DS_BIT);
  _delay_us(500);
}

void OneWireOutByte(uint8_t d)
{
  uint8_t n;
  for (n = 8; n != 0; n--)
  {
    if ((d & 0x01) == 1)
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(5);
      DDRB &= ~_BV(DS_BIT);
      _delay_us(60);
    }
    else
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(60);
      DDRB &= ~_BV(DS_BIT);
    }
    d = d >> 1;
  }
}


uint8_t OneWireInByte()
{
  uint8_t d, n, b;
  for (n = 0; n < 8; n++)
  {
    PORTB &= ~_BV(DS_BIT);
    DDRB |= _BV(DS_BIT);
    _delay_us(5);
    DDRB &= ~_BV(DS_BIT);
    _delay_us(5);
    b = ((PINB & _BV(DS_BIT)) != 0);
    _delay_us(50);
    d = (d >> 1) | (b << 7);
  }
  return (d);
}


word GetTemp() {
  uint8_t DSdata[2];
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0x44);
  PORTB |= _BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_ms(1000); // если хотим ждать когда датчик посчитает температуру.
  DDRB &= ~_BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0xbe);
  DSdata[0] = OneWireInByte();
  DSdata[1] = OneWireInByte();
  word TReading = (word)(DSdata[1] << 8) + DSdata[0];
  if ((word)(TReading & 0x8000) == (word)(0x8000)) {
    TReading = (~TReading) + (word)1;
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10;
  } else {
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10 + (word)2000;
  }
  return TReading;
}

вопрос? что за ядро такое и куда функцию - sleep_bod_disable() заныкал )))

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

ua6em пишет:

andycat пишет:

Наконец то пришли правильные стабилизаторы с микроамперными токами потребления в покое,

10 мкА без нагрузки, 16 мкА в спящем режиме всей схемы.

Уличный термометр, каждые ~17 минут отправляющий данные, скетч:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/io.h>
#include <util/delay.h>     /* for _delay_us() */

#define periodusec 400 // mcs
#define DS_BIT         4 // pin 3
#define RC_BIT         3 // pin 2

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// PB0 pin 5
#define PB0_OUT sbi(DDRB,PB0)
#define PB0_LOW cbi(PORTB,PB0)
// PB1 pin 6 - EN pin RFunit WL118
#define PB1_OUT sbi(DDRB,PB1)
#define PB1_HIGH sbi(PORTB,PB1)
#define PB1_LOW cbi(PORTB,PB1)
// PB2 pin 7
#define PB2_OUT sbi(DDRB,PB2)
#define PB2_LOW cbi(PORTB,PB2)
// PB3 pin 2
#define PB3_OUT sbi(DDRB,PB3);
#define PB3_LOW cbi(PORTB,PB3);
// PB4 pin 3
#define PB4_OUT sbi(DDRB,PB4)
#define PB4_IN cbi(DDRB,PB4)
#define PB4_HIGH sbi(PORTB,PB4)
#define PB4_LOW cbi(PORTB,PB4)

#define TimerCountSec 1027 // ~17min delay start by sec
word CurrentTime = 0;

void ExecFunc() {
  // установка режима для ds
  DDRB |= _BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  DDRB &= ~_BV(DS_BIT);
  // get temp and send
  PB1_OUT; PB1_HIGH; // ON RF unit
  word TReading = GetTemp();
  sendRC((unsigned long)(TReading + (word)11500)); // отправляем данные
  // OFF pins
  OneWireReset();
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
}

void CalcTimer() {
  ++CurrentTime;
  if (((CurrentTime + 1UL) * 8UL) >= TimerCountSec) {
    CurrentTime = 0;
    ExecFunc();
  }
}

ISR (WDT_vect)
{
  wdt_disable();  // disable watchdog
}

void setup () {
  // OFF pins
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
  unsigned long delp = millis(); while ((millis() - delp) <= 1000); // pause for enable all device and get temp to clock
  // first run
  ExecFunc();
  delp = millis(); while ((millis() - delp) <= 4000); // pause for enable all device and get temp to clock
  // second run
  ExecFunc(); // for exactly get temp
}

void loop ()
{
  CalcTimer();
  cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF
  setup_watchdog(9);
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts (); // timed sequence follows
  sleep_enable();
  sleep_bod_disable();
  interrupts ();  // guarantees next instruction executed
  sleep_cpu ();  // cancel sleep as a precaution
  sleep_disable();
}


// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
  byte bb; int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE); ww = bb;
  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCR |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCR = bb; WDTCR |= _BV(WDIE);
}


void sendRC(unsigned long data) { // Отправка данных по радиоканалу RCswitch. Двоичный протокол
  DDRB |= _BV(RC_BIT);
  data |= 3L << 20; // ?
  unsigned short repeats = 1 << (((unsigned long)data >> 20) & 7);
  data = data & 0xfffff;
  unsigned long dataBase4 = 0; uint8_t i;
  for (i = 0; i < 20; i++) {
    dataBase4 <<= 1;
    dataBase4 |= (data % 2);
    data /= 2;
  }
  unsigned short int j;
  for (j = 0; j < repeats; j++) {
    data = dataBase4; uint8_t i;
    for (i = 0; i < 20; i++) {
      switch (data & 1) {
        case 0:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec * 3);
          break;
        case 1:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec * 3);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec);
          break;
      }
      data >>= 1;
    }
    PORTB |= _BV(RC_BIT);
    _delay_us(periodusec);
    PORTB &= ~_BV(RC_BIT);
    _delay_us(periodusec * 31);
  }
}

// OneWire функции:

void OneWireReset()
{
  PORTB &= ~_BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_us(500);
  DDRB &= ~_BV(DS_BIT);
  _delay_us(500);
}

void OneWireOutByte(uint8_t d)
{
  uint8_t n;
  for (n = 8; n != 0; n--)
  {
    if ((d & 0x01) == 1)
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(5);
      DDRB &= ~_BV(DS_BIT);
      _delay_us(60);
    }
    else
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(60);
      DDRB &= ~_BV(DS_BIT);
    }
    d = d >> 1;
  }
}


uint8_t OneWireInByte()
{
  uint8_t d, n, b;
  for (n = 0; n < 8; n++)
  {
    PORTB &= ~_BV(DS_BIT);
    DDRB |= _BV(DS_BIT);
    _delay_us(5);
    DDRB &= ~_BV(DS_BIT);
    _delay_us(5);
    b = ((PINB & _BV(DS_BIT)) != 0);
    _delay_us(50);
    d = (d >> 1) | (b << 7);
  }
  return (d);
}


word GetTemp() {
  uint8_t DSdata[2];
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0x44);
  PORTB |= _BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_ms(1000); // если хотим ждать когда датчик посчитает температуру.
  DDRB &= ~_BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0xbe);
  DSdata[0] = OneWireInByte();
  DSdata[1] = OneWireInByte();
  word TReading = (word)(DSdata[1] << 8) + DSdata[0];
  if ((word)(TReading & 0x8000) == (word)(0x8000)) {
    TReading = (~TReading) + (word)1;
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10;
  } else {
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10 + (word)2000;
  }
  return TReading;
}

вопрос? что за ядро такое и куда функцию - sleep_bod_disable() заныкал )))


Не очень понял вопрос про функцию, а ядро скачивал с сайта чип и дип, там примеры разработок.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andycat пишет:
ua6em пишет:

andycat пишет:

Наконец то пришли правильные стабилизаторы с микроамперными токами потребления в покое,

10 мкА без нагрузки, 16 мкА в спящем режиме всей схемы.

Уличный термометр, каждые ~17 минут отправляющий данные, скетч:

#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/io.h>
#include <util/delay.h>     /* for _delay_us() */

#define periodusec 400 // mcs
#define DS_BIT         4 // pin 3
#define RC_BIT         3 // pin 2

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// PB0 pin 5
#define PB0_OUT sbi(DDRB,PB0)
#define PB0_LOW cbi(PORTB,PB0)
// PB1 pin 6 - EN pin RFunit WL118
#define PB1_OUT sbi(DDRB,PB1)
#define PB1_HIGH sbi(PORTB,PB1)
#define PB1_LOW cbi(PORTB,PB1)
// PB2 pin 7
#define PB2_OUT sbi(DDRB,PB2)
#define PB2_LOW cbi(PORTB,PB2)
// PB3 pin 2
#define PB3_OUT sbi(DDRB,PB3);
#define PB3_LOW cbi(PORTB,PB3);
// PB4 pin 3
#define PB4_OUT sbi(DDRB,PB4)
#define PB4_IN cbi(DDRB,PB4)
#define PB4_HIGH sbi(PORTB,PB4)
#define PB4_LOW cbi(PORTB,PB4)

#define TimerCountSec 1027 // ~17min delay start by sec
word CurrentTime = 0;

void ExecFunc() {
  // установка режима для ds
  DDRB |= _BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  DDRB &= ~_BV(DS_BIT);
  // get temp and send
  PB1_OUT; PB1_HIGH; // ON RF unit
  word TReading = GetTemp();
  sendRC((unsigned long)(TReading + (word)11500)); // отправляем данные
  // OFF pins
  OneWireReset();
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
}

void CalcTimer() {
  ++CurrentTime;
  if (((CurrentTime + 1UL) * 8UL) >= TimerCountSec) {
    CurrentTime = 0;
    ExecFunc();
  }
}

ISR (WDT_vect)
{
  wdt_disable();  // disable watchdog
}

void setup () {
  // OFF pins
  PB0_OUT; PB0_LOW;
  PB1_OUT; PB1_LOW;
  PB2_OUT; PB2_LOW;
  PB3_OUT; PB3_LOW;
  PB4_IN; PB4_LOW;
  unsigned long delp = millis(); while ((millis() - delp) <= 1000); // pause for enable all device and get temp to clock
  // first run
  ExecFunc();
  delp = millis(); while ((millis() - delp) <= 4000); // pause for enable all device and get temp to clock
  // second run
  ExecFunc(); // for exactly get temp
}

void loop ()
{
  CalcTimer();
  cbi(ADCSRA, ADEN); // switch Analog to Digitalconverter OFF
  setup_watchdog(9);
  wdt_reset();  // pat the dog
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts (); // timed sequence follows
  sleep_enable();
  sleep_bod_disable();
  interrupts ();  // guarantees next instruction executed
  sleep_cpu ();  // cancel sleep as a precaution
  sleep_disable();
}


// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
  byte bb; int ww;
  if (ii > 9 ) ii = 9;
  bb = ii & 7;
  if (ii > 7) bb |= (1 << 5);
  bb |= (1 << WDCE); ww = bb;
  MCUSR &= ~(1 << WDRF);
  // start timed sequence
  WDTCR |= (1 << WDCE) | (1 << WDE);
  // set new watchdog timeout value
  WDTCR = bb; WDTCR |= _BV(WDIE);
}


void sendRC(unsigned long data) { // Отправка данных по радиоканалу RCswitch. Двоичный протокол
  DDRB |= _BV(RC_BIT);
  data |= 3L << 20; // ?
  unsigned short repeats = 1 << (((unsigned long)data >> 20) & 7);
  data = data & 0xfffff;
  unsigned long dataBase4 = 0; uint8_t i;
  for (i = 0; i < 20; i++) {
    dataBase4 <<= 1;
    dataBase4 |= (data % 2);
    data /= 2;
  }
  unsigned short int j;
  for (j = 0; j < repeats; j++) {
    data = dataBase4; uint8_t i;
    for (i = 0; i < 20; i++) {
      switch (data & 1) {
        case 0:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec * 3);
          break;
        case 1:
          PORTB |= _BV(RC_BIT);
          _delay_us(periodusec * 3);
          PORTB &= ~_BV(RC_BIT);
          _delay_us(periodusec);
          break;
      }
      data >>= 1;
    }
    PORTB |= _BV(RC_BIT);
    _delay_us(periodusec);
    PORTB &= ~_BV(RC_BIT);
    _delay_us(periodusec * 31);
  }
}

// OneWire функции:

void OneWireReset()
{
  PORTB &= ~_BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_us(500);
  DDRB &= ~_BV(DS_BIT);
  _delay_us(500);
}

void OneWireOutByte(uint8_t d)
{
  uint8_t n;
  for (n = 8; n != 0; n--)
  {
    if ((d & 0x01) == 1)
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(5);
      DDRB &= ~_BV(DS_BIT);
      _delay_us(60);
    }
    else
    {
      PORTB &= ~_BV(DS_BIT);
      DDRB |= _BV(DS_BIT);
      _delay_us(60);
      DDRB &= ~_BV(DS_BIT);
    }
    d = d >> 1;
  }
}


uint8_t OneWireInByte()
{
  uint8_t d, n, b;
  for (n = 0; n < 8; n++)
  {
    PORTB &= ~_BV(DS_BIT);
    DDRB |= _BV(DS_BIT);
    _delay_us(5);
    DDRB &= ~_BV(DS_BIT);
    _delay_us(5);
    b = ((PINB & _BV(DS_BIT)) != 0);
    _delay_us(50);
    d = (d >> 1) | (b << 7);
  }
  return (d);
}


word GetTemp() {
  uint8_t DSdata[2];
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0x44);
  PORTB |= _BV(DS_BIT);
  DDRB |= _BV(DS_BIT);
  _delay_ms(1000); // если хотим ждать когда датчик посчитает температуру.
  DDRB &= ~_BV(DS_BIT);
  PORTB &= ~_BV(DS_BIT);
  OneWireReset();
  OneWireOutByte(0xcc);
  OneWireOutByte(0xbe);
  DSdata[0] = OneWireInByte();
  DSdata[1] = OneWireInByte();
  word TReading = (word)(DSdata[1] << 8) + DSdata[0];
  if ((word)(TReading & 0x8000) == (word)(0x8000)) {
    TReading = (~TReading) + (word)1;
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10;
  } else {
    TReading = (((word)6 * TReading) + TReading / (word)4) / (word)10 + (word)2000;
  }
  return TReading;
}

вопрос? что за ядро такое и куда функцию - sleep_bod_disable() заныкал )))

Не очень понял вопрос про функцию, а ядро скачивал с сайта чип и дип, там примеры разработок.

разобрался! этот код под attiny25/45/85 )))
Второй вопрос, что за правильные стабилизаторы?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

83,55 руб. 40%СКИДКА | Высокоэффективный преобразователь питания, 500 мА, от 0,8-3,3 В до 3,3 В, PFM, повышающий преобразователь для ds18b20, dht22, STM32, FPGA, CPLD
https://a.aliexpress.com/_AaZyIt

Не смог найти ссылку, но вроде оно.

selan61
Offline
Зарегистрирован: 15.12.2017

Для ATtiny13 используется MicroCore, а для ATtiny2313A используется ATТinyCore. Что нужно настроить, что бы скетчи работали на ATtiny2313A?

mir0tv0rec
Offline
Зарегистрирован: 19.09.2018

Всем доброго времени!
Пытаюсь сделать тахометр для шпинделя станка (по факту частотомер). Т.к. купить "из комплекта" зеленое земноводное не дает. Драйвер шпинделя выдает меандр, ну или почти (на низких) частотах от 0 до 400Гц 10В.  Обороты, в теории, до 12000. Соответственно гдо-то 1/30 соотношение.
Накидал программку, но не уcтраивает точность - прыгают значения частоты порядка +-20 Гц. А это, сами понимаете, может вылезти в погрешность оборотов в минуту порядка 600. Что не приемлемо.

Сначала сделал в режиме FAST PWM. Из-за погрешности решил более точно подогнать измерение времени и переделал на режим CTC. Посчитал по формуле частоту из ДШ получилось, что для 100кГц нужно установить OCR0A = 47. Формула расчета из ДШ (fOCnx = fclk_I/O / (2 * N * (1 + OCRnx)). Но при таком значении не работает. Думал, что не запускается таймер - на дисплее нули. Но потом случайно изменил на 100 и все заработало, причем примерно на расчетной частоте.  Где я накосячил? Пока оставил только счетчикс выводом на дисплей (MAX7219), чтобы таймер откалибровать.
 

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define T_IN  PB1 // вход частотомера
#define DIN   PB0 // 
#define CS    PB2 // выходы на индикатор (MAX7219)
#define CLK   PB3 //

#define PER   250 //  период времени измерения
 
volatile uint32_t tCounter;     // счетчик времени (0.000001s)
volatile uint16_t sCounter;     // счетчик времени (1s)
volatile uint16_t edgecounter;  // ссчетчик импульсов на T_IN
volatile uint16_t freq;         // частота на выходе драйвера   
volatile uint8_t  ssCount;      // кол-во измерений для усреднения
volatile uint16_t rpm;          // обороты в минуту   

void WriteBit16(byte reg, byte data){  
  PORTB &= ~(1 << CLK);
  PORTB &= ~(1 << CS);
  for (int i = 7; i >= 0; i--){
    if(((reg >> i) & 1) == 1){
      PORTB |= (1 << DIN);
    }//end if
    else{
      PORTB &= ~(1 << DIN);
    }//end else
    PORTB |=(1 << CLK);
    PORTB &= ~(1 << CLK);
  }//end for
  
  for (int i = 7; i >= 0; i--){
    if(((data >> i) & 1) == 1){
      PORTB |= (1 << DIN);
    }//end if
    else{
      PORTB &= ~(1 << DIN);
    }//end else
    PORTB |=(1 << CLK);
    PORTB &= ~(1 << CLK);
  }//end for
  PORTB |=(1 << CS);
  PORTB &= ~(1 << CLK);
  PORTB &= ~(1 << DIN);
}//end  void WriteBit16()

void dec(long decimal){
  //WriteBit16(0x08,15);
  //WriteBit16(0x07,15/*decimal/1000000%10*/);  // 15 - пустой разряд (без свечения) 0x0F
  //WriteBit16(0x06,15/*decimal/100000%10*/);   // 15 - пустой разряд (без свечения)
  WriteBit16(0x05,decimal/10000%10);
  WriteBit16(0x04,decimal/1000%10/*+0x80 точка*/);
  WriteBit16(0x03,decimal/100%10);
  WriteBit16(0x02,decimal/10%10);
  WriteBit16(0x01,decimal%10);
}//end void dec(long decimal)
 
 
ISR(TIM0_COMPA_vect){
  
  tCounter++; //~1ms
  
  if (tCounter > 99999){  // ~1с
    tCounter = 0; // обнуляем счетчик
    ssCount++;  // секунда для отладки
    /*
    if (ssCount > 99){
      freq += edgecounter; // частота - кол-во импульсов за промежуток времени...
      edgecounter = 0;     // обнуляем счетчик импульсов на входе PB1 (INT0) ~ каждую секунду
      ssCount = 0;
      sCounter++;
      if (sCounter > 9){
        rpm = freq;
        freq = 0;
        sCounter = 0;
      }//end if
    }//end if
    */
  }//end if
  
}//end ISR(TIM0_COMPA_vect) 


// Обработчик прерывания INT0
/*
ISR(INT0_vect){
  edgecounter++;
}//end ISR(INT0_vect)
*/
 
void setup(){

  //DDRB &= ~(1 << T_IN);  // порт частотометра на вход (на всякий случай)
  DDRB |= (1 << DIN) | (1 << CS) | (1 << CLK);  // порты управления дисплеем на выход
  PORTB |= (1 << CS); // на CS пин высокий уровень
  PORTB &= ~(1 << CLK) | (1 << DIN);  // на CLK и  DIN - низкий
  
 
  WriteBit16(0x0F,0x00); // Тест выкл.
  WriteBit16(0x0C,0x01); // Вкл. индик.
  WriteBit16(0x0B,0x04); // кол-во разрядов (5)
  WriteBit16(0x09,0x1F); // Дешифраторы вкл. 5 разрядов
  WriteBit16(0x0A,0x02); // яркость (0-15)
  
  cli(); //отключаем прерывания глобально

  // TIM0
  TCNT0 = 0;  // обнуляем счетный регистр
  OCR0A = 99; // для частоты таймера 100 кГц (предделитель 96)
  TCCR0A |= (1 << WGM01);   // режим CTC (сброс по совпадению)
  TCCR0B |= (1 << CS00);    // предделитель 1 (частота для CTC: частота чипа /(2*делитель*(1+OCR0A))
  TIMSK0 |= (1 << OCIE0A);  // вкл. прерывание по совпадению таймера
  
  
  //INT0
  //MCUCR |= (1 << ISC01)/* | (1 << ISC00)*/;    // прерывание по восходящему фронту
  //GIMSK |= (1 << INT0);     // включаем прерывание
    
  sei(); //включаем прерывания глобально 

}//end setup()
 
void loop(){
  
  dec(ssCount);
  _delay_ms(PER);
  
}//end loop()