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

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

MkTwo пишет:

уточните пожалуйста насчёт вообще системы заливки скетчей напрямую в микроконтроллеры - как я думал, загрузчик, который заливается из Arduino IDE это своеобразный компилятор скетча ардуино в язык микроконтроллера, а получается что можно скетчи напрямую в мк заливать? зачем тогда нужен загрузчик вообще?

Да, скетчи можно загружать напрямую. Нет, загрузчик это не "своеобразный компилятор скетча ардуино в язык микроконтроллера". Загрузчик нужен только для того, чтобы загружать скетч без программатора. То есть, чтобы загружать его через USB-UART преобразователь (микросхема такая), который есть на плате Ардуино. Это сделано только для облегчения - чтобы не покупать специально программатор, а вставил плату в USB и всё. На плате должен быть сам микроконтроллер и USB-UART преобразователь. Именно так и сделано на платах Ардуино. 

Непосредственно на язык программирования, исходный код, компиляцию загрузчик абсолютно никак не влияет. Код скомпилированный в Arduino IDE можно загрузить в отдельный микроконтроллер ATmega/ATtiny в не зависимости от того, есть ли в нём загрузчик или нет. От этого зависит только способ загрузки. Если загрузчика нет - загружать программатором, если загрузчик есть - загружать через USB.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

MkTwo, в этой теме всё уже обсуждалось. Вот например аналог вашего первого вопроса тыц и в следующем сообщении ответ. И про частоту тоже было. наверняка у вас фуз CKDIV8 включен. Можно много интересного узнать просто перечитав тему с начала.

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

MkTwo пишет:

получается, если есть программатор, то можно просто выбрать "Программатор - USBasp" и заливать по кнопке "Загрузить через программатор"? никаких загрузчиков записывать предварительно не надо? а то я на ATmega8A сначала записал загрузчик, а потом заливаю скетчи как в обычную ардуино...

Да, именно так. Для ATmega8A тоже загрузчик не нужен. "а потом заливаю скетчи как в обычную ардуино" - это если через USB-UART преобразователь. Если же Вы продолжаете заливать скетчи через программатор USBasp, то в загрузчике нет никакого смысла, да он уже и затёрся поверх другим кодом.

MkTwo пишет:

и ещё вопрос - залил blink в ардуино, там delay(1000); стандартный, так он мигает примерно в 10 раз реже... я как понимаю эта тема известная наверное, можете дать ссылку где можно почитать про это?

Это потому, что реальная частота микроконтроллера не совпадает с той, которая задана в Arduino IDE. Частота микроконтроллера настраивается через "фьюзы" (fuse). Эти фьюзы настраиваются (прошиваются) через программатор, двумя способами. Либо вручную с помощью специальной программы (напр. SinaProg, AvrdudeProg и другие), либо через запись загрузчика в Arduino IDE. То есть, если Вы в Arduino IDE выберете в настройках ATtiny13A 1,2МГц и запишете загрузчик, то вместе с загрузчиком прошьются фьюзы на частоту 1,2МГц. Я например загрузчик не прошиваю, а фьюзы прошиваю вручную через вышеозначенные программы. Через них же можно прошить уже скомпилированную прошивку (в любой среде, а не только Arduio IDE) в формате *.hex

nik182
Offline
Зарегистрирован: 04.05.2015

Получил несколько Attiny25. Для отладки потребовалось выводить регистры и переменные. Перекопал кучу вариантов. Пришлось делать обрезание всего, чего можно, что бы влезло в память. Получилось 70 байт на вывод одного байта на скорости 19200 и ещё 120 байт на вывод переменной в десятичном виде. Не зависит от типа процессора. Не использует таймеры. Для другой тактовой частоты или скорости обмена надо изменить константу br , но  не более 255. Если в программе используется delayMicrosecods(), то ещё можно сэкономить, заменив del15() на неё. В этом случае br надо увеличить в 1.6 раза. 

 


#define br 33 //19200@8MHz
#define TxPin 0


void del15(uint8_t d)
{
  for (uint8_t __volatile__ j=0; j < d ; j++) {asm("NOP");};      
}

void printu(uint16_t u){
  byte d[4];
 for(byte i = 0; i<4; i++){d[i]= u%10 + 0x30 ; u/=10;};
 for(byte i = 4; i>0; i--)  uart_send_byte(d[i-1]);
}

void uart_send_byte (unsigned char data)
{
  unsigned char i;
      PORTB &= ~(1 << TxPin);
      del15(br);
  for (i = 0; i < 8; i++)
  {
    if (data & 1)
      PORTB |= 1 << TxPin ;
    else
      PORTB &= ~(1 << TxPin);
  
    data >>= 1;
    del15(br);
  }
  PORTB |= 1 << TxPin ;
  del15(br);
}

int main(void){
    DDRB |= 1 << TxPin ;

  while(1) {
   byte b;
   b++; 
   printu (b);
    uart_send_byte (0x20); //Пробел
   uart_send_byte (10);  uart_send_byte (13); // LF - CR

  
 };
  return(0);

}

 

energy74
Offline
Зарегистрирован: 14.09.2016

jeka_tm пишет:

все просто. для шим на PB0 нужно сделать так

void setup(){ 
  
             //Настройка порта
PORTB=0x00;  //записать в весь порт В 0
DDRB=0x01;   //настроить порт В 0x01: по другому 000001 (1 означает выход, 0 вход)
             //нумерация слева направо. получается PB0 сделать выходом, остальные входы

//Настройка аппаратного ШИМ 
TCCR0A=0x83;  //настраиваем аппартанный шим на PB0 с частотой 37,5кГц(аппаратный шим только на PB0 и PB1)
TCCR0B=0x01;  //на PB1 (второй шим) ничего делать не надо
OCR0A=0x00;   //записать в регистр OCR0A 0 (это регистр задает ширину шим)
              //0 соответствует 0% ширине, 255 ширине 100% импульсов в шим
} 

void loop() 
{ 
  OCR0A=127;  //сделаем шим на PB0 шириной 50%, меандр короче получили
              //запишите другое чисто от 0 до 255 этим вы регулируете шим
} 

 

 

Если сохранилось, выложи пожалуйста исходник с поста 134 полностью, а то что-то Programmers notepad ругается. Вроде и шаблон стандартный, но не хочет компилироваться. В основном опыт прошивки готовых hex. И еще вопрос. Как с помощью этого кода можно програмно, с небольшими прыжками подбирать частоту (+-100 Гц) , т.е. 37,4 или 37.6 кГц? Для генерации я в основном пользовался кодом типа:

PORTB &= ~_BV(PB0);
_delay_us(16);
PORTB |= _BV(PB0);
_delay_us(16);

т.е методом подбора задержок, но скачки частоты большие. А тиньку13 обвешивать еще чем-то не хочется из-за минимализации.
Просто есть задача построить датчик на генераторе (вместо ne555).  На 555, при нагреве немного уходит частота, плюс он кушает хорошо .) Частота  через Ик светодиод должна быть направлена на TSOP 4836 и должна его "глушить" , т.е. запирать выход на 0. Это происходит на определенной частоте.Точную  частоту я  вычисляю на макетке с ne555. Затем эту частоту хочу запрограммировать в тини13. Диапазон Частот у разных TSOP немного колеблется. Датчик действует по принципу ИК датчика препятсвия с расстоянием приемник-излучатель 5 см. Сработка должна быть моментальная. В инете накопал и перепробовал кучу схем локаторов и барьеров на тини13 и др., но там  есть недостатки в виде задержки сработки из-за анализа переданных и принятых пакетов или из-за помех от наружного освещения. Кто может чем-то помочь?

energy74
Offline
Зарегистрирован: 14.09.2016

Сам себе ответил. Был неисправен TSOP4836, поэтому не смог его "заглушить". Сгенерировал код простой мигалки

PORTB &= ~_BV(PB0);
_delay_us(16);
PORTB |= _BV(PB0);
_delay_us(16);

получил частоту около 37кГц. Кстати TSOP36 запирается при частотах от 35 до 38 кгц. При значениях 16 микросекунд, максимальная сила.

Правда интересно как 37 кгц заделать с помощью счетчиков?

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

energy74, вы эту тему читали? А зря, много всего интересного. Тут ответы почти на все возможные вопросы. В том числе на ваш.

energy74
Offline
Зарегистрирован: 14.09.2016

Спасибо, до 664 поста не дотянул. Это ардуиновский код? А то WinAvr не принимает. Если не трудно, объясните как поменять в исходнике на привычные int main (void) и while и т.п., чтоб самому потом скомпилировать.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

energy74, у вас в вопросе уже содержится 99% ответа. Поменять первую строчку на int main(void){  А 7-я строка не нужна.

energy74
Offline
Зарегистрирован: 14.09.2016

Благодарю за подсказку. WinAvr  скомпилировал.

#include <avr/io.h>
int main (void){
DDRB|=(1<<PB0); //PB0- OUTPUT mode
TCCR0A=(1<<COM0B0)|(1<<COM0A0)|(1<<WGM01); // CTC mode, OC0A OC0B toggle enable
TCCR0B=(1<<FOC0A)|(1<<CS01); //divider=8
OCR0A=15;
}

На этом коде частота 37.5 кГц. Жаль только что при изменении OCR0A, большие скачки.

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

energy74 пишет:

На этом коде частота 37.5 кГц. Жаль только что при изменении OCR0A, большие скачки.

Ну так сделайте делитель единицу, будет меньше шаг. Написано ж всё.

energy74
Offline
Зарегистрирован: 14.09.2016

надо попробовать. Чуть освобожусь, поковыряюсь в делителях. В понедельник отпишусь.

energy74
Offline
Зарегистрирован: 14.09.2016

dimax пишет:

Ну так сделайте делитель единицу, будет меньше шаг.

Вроде так получше. Со значением OCR0A=130,  частота 36.640, то что надо.

#include <avr/io.h>
int main (void)
{
DDRB|=(1<<PB0); //PB0- OUTPUT mode
TCCR0A=(1<<COM0B0)|(1<<COM0A0)|(1<<WGM01); // CTC mode, OC0A OC0B toggle enable
TCCR0B=(1<<FOC0A)|(1<<CS00); //cs00-делитель 1
OCR0A=130;
}

Спасибо, что направил в нужном направлении.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Простите, если окажестя не сильно нужным, но вот некий код.

Быть может кому-то понравится. ;)

Это просто термометр, на Далласе и с 1602 экраном.

Не спешите говорить "ФУ!!!!!".

Он работает на Тиньке13 и занимает 928 байт, еще останется место для термостата ;) ну если кому надо.

И 1wire и i2c и lcd, сделано програмно, и, если убрать Атмеловскую специфику с регистрами, и заменить на digitalWrite() и т.д.

то будет полная переносимость. В Тиньку переносимый вариант не поместился, хоть я и старался.

Библиотека i2c, если сравнивать с лучшей софтовой реализацией - SoftI2C-master, то написана только в IDE и занимает столько же места.

Я еще не проверял ее с другими типами i2c устройств.

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

----------------------------

Ну, типа все, а теперь код.


#define _NOP() asm volatile("nop")

//это у меня диагностическое моргание ледом на второй ноге тиньки
#define _LED()      (DDRB  |= 0B00001000)  
#define _LED_ON()   (PORTB |= 0B00001000)
#define _LED_OFF()  (PORTB &= 0B11110111)
  
 
// delay() для тиньки и свой нормальный, а delayMicroseconds() дурной
//поэтому свой нужен

//а вот глобального такого дефайна может и не быть, как ни странно, так для страховки завел
//#define F_CPU 4800000UL
#define LOOP_CYCLES 8
#define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))

inline __attribute__((gnu_inline)) void asm_delay(uint16_t delay){
  uint16_t u=us(delay);
do _NOP(); while(delay--);
}

#define wdelay_us(x)  asm_delay(us(x))
#define wdelay(x) delay(x)


/*****************************************************/
//дальше мелкий вариант i2c на любых ногах
//если работать через функции (закоментировано) то будет переносимость хоть куда

#define IICR  1
#define IICW  0
// на 100КГц примерно по 4 мкс нужно держать уровни SCL - со скоростью сами экспериментируйте, мне не нужно было
#define I2CDelay()  wdelay_us(4)
#define SDA_Pin   0
#define SCL_Pin   1

/*
#define SDA_In()    digitalRead(SDA_Pin)
#define SCL_In()    digitalRead(SCL_Pin)

     void SDA_Hi()  { digitalWrite(SDA_Pin, HIGH); pinMode(SDA_Pin,  INPUT);}
     void SDA_Lo()  { digitalWrite(SDA_Pin, LOW ); pinMode(SDA_Pin, OUTPUT);}
     void SCL_Hi()  { digitalWrite(SCL_Pin, HIGH); pinMode(SCL_Pin,  INPUT);}
     void SCL_Lo()  { digitalWrite(SCL_Pin, LOW ); pinMode(SCL_Pin, OUTPUT);}
*/
#define SDA_In()    (PINB & 0B00000001)
#define SCL_In()    (PINB & 0B00000010)

     inline void SDA_Hi()  { PORTB |= 0B00000001; DDRB &= 0B11111110;}
     inline void SDA_Lo()  { PORTB &= 0B11111110; DDRB |= 0B00000001;}
     inline void SCL_Hi()  { PORTB |= 0B00000010; DDRB &= 0B11111101;}
     inline void SCL_Lo()  { PORTB &= 0B11111101; DDRB |= 0B00000010;}

void I2CInit (void)
{
    SDA_Hi();
    SCL_Hi();
}


void I2CStart (void)
{
  SCL_Hi();
  while (!SCL_In());
  I2CDelay();
  SDA_Lo();
  SCL_Lo();  
}
 
void I2CStop (void)
{
  I2CDelay();
  SCL_Hi();
  I2CDelay();
  SDA_Hi();
  I2CDelay();
}

boolean I2CWrite(byte b)
{
  byte i = 1<<7;
  boolean ack=0;

  while(i)
    {
      I2CDelay();
      if (b & i) SDA_Hi(); else SDA_Lo();
      I2CDelay();
      SCL_Hi();
      I2CDelay();
      SCL_Lo();
      
      i>>=1; 
    }
  SDA_Hi();
  I2CDelay();
  SCL_Hi();

  if ( SDA_In()==0 ) ack = 1;
  I2CDelay();
  SCL_Lo();
  SDA_Lo();
  return ack;
}

byte I2CRead(boolean ack)
{
  byte i=8;
  byte b=0;
  
  while(i--)
  {
   I2CDelay();
   SCL_Hi();
   if (SDA_In()) b |= 1;
   b <<= 1;
   I2CDelay();
   SCL_Lo();
  }
  if (ack) SDA_Lo();
  else SDA_Hi();
  I2CDelay();
  SCL_Hi();
  I2CDelay();
  SCL_Lo();
  SDA_Lo();
  return b;
}
/*************************************/
//Все ниже - для LCD дисплея на i2c. Принцип ясен, все легко переделать под свои варианты
//идеи взяты, ясен хрен, из стандарной библиотеки. Управление подсветкой похерено ради экономии ;)
#define LCDADDR 0x27


void lcdRaw(byte b)
  {
    I2CStart();
    I2CWrite(LCDADDR<<1);
    I2CWrite(b|8);
    I2CStop();
  }

void lcdWrite4(byte b)
  {
    lcdRaw  (b);
    wdelay_us(5);
    lcdRaw  (b| 4);
    wdelay_us(5);
    lcdRaw( (b&!4));
    wdelay_us(40);
  }
void lcdCmd(byte b)
  {
    lcdWrite4(b&0xf0);
    lcdWrite4((b&0xf)<<4);  
  }
void lcdDate(byte b)
  {
    lcdWrite4 (b&0xf0     |1);
    lcdWrite4((b&0x0f)<<4 |1);  
  }

/*********************************************/
//это для далласа, много переделывал то, что нашел в сети, там были ошибки, первого автора уже не помню. Прости братан!
//сделано для тиньки, поэтому нет различия по адресам градусников.

#define THERM_CMD_CONVERTTEMP       0x44
#define THERM_CMD_RSCRATCHPAD       0xbe
#define THERM_CMD_WSCRATCHPAD       0x4e
#define THERM_CMD_CPYSCRATCHPAD     0x48
#define THERM_CMD_RECEEPROM         0xb8
#define THERM_CMD_RPWRSUPPLY        0xb4
#define THERM_CMD_SEARCHROM         0xf0
#define THERM_CMD_READROM           0x33
#define THERM_CMD_MATCHROM          0x55
#define THERM_CMD_SKIPROM           0xcc
#define THERM_CMD_ALARMSEARCH       0xec


#define THERM_PORT PORTB
#define THERM_DDR DDRB
#define THERM_PIN PINB
#define THERM_DQ PB4

#define THERM_INPUT_MODE() THERM_DDR&=~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE() THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW() THERM_PORT&=~(1<<THERM_DQ)
#define THERM_HIGH() THERM_PORT|=(1<<THERM_DQ)


uint8_t therm_reset(){

uint8_t i;


THERM_LOW();
THERM_OUTPUT_MODE();
wdelay_us(500);


THERM_INPUT_MODE();
wdelay_us(40);


i=(THERM_PIN & (1<<THERM_DQ));

wdelay_us(500);

return i;
}


uint8_t therm_read_byte(void){
uint8_t i=8, n=0;
while(i--){

n>>=1;

THERM_LOW();
THERM_OUTPUT_MODE();
wdelay_us(1);

THERM_INPUT_MODE();
wdelay_us(9);

if(THERM_PIN&(1<<THERM_DQ)) n |= 1<<7;

wdelay_us(51);
}

return n;
}

void therm_write_byte(uint8_t byte){
uint8_t i=8;

while(i--){

THERM_LOW();
THERM_OUTPUT_MODE();
wdelay_us(5);

if(byte&1) THERM_INPUT_MODE();

wdelay_us(55);
THERM_INPUT_MODE();
byte>>=1;
wdelay_us(1);
}
}

#define therm_ask_temperature()          \
therm_reset();                           \
therm_write_byte(THERM_CMD_SKIPROM);     \
therm_write_byte(THERM_CMD_CONVERTTEMP);



int therm_read_temperature()
{

union {
  uint8_t t[2];
  int r;
} tc;

therm_reset();
therm_write_byte(THERM_CMD_SKIPROM);
therm_write_byte(THERM_CMD_RSCRATCHPAD);

//Read Scratchpad (only 2 first bytes)

tc.t[0]=therm_read_byte();
tc.t[1]=therm_read_byte();
therm_reset();

return (tc.r);
}
/*********************************************/


void setup() {

I2CInit();
//где-то видел, что нехилая задержка нужна, чтобы дисплей проснулся, проверяйте сами, если нужно
wdelay(1000);

//init LCD acc docs
//just like lcd_i2c standart lib
lcdWrite4(0x30);
 wdelay(5);
 
 lcdWrite4(0x30);
 wdelay(5);
 
 lcdWrite4(0x30);
 wdelay(1);

 lcdWrite4(0x20);
 wdelay(1);
 
 //set 4 dig
 lcdCmd(0x20);
 lcdCmd(0x0c);
 lcdCmd(0x01);
 wdelay(1);
 lcdCmd(0x06);
 lcdCmd(0x02); 
}

void loop() {
int t;
  //запрос на конвертирование
  therm_ask_temperature();
  wdelay(750);
  t = therm_read_temperature();

static int to=0;
byte d1=0,d10=0,dd=0;

if (to != t)
{ to=t;
 lcdCmd(0x01);
  wdelay(1);

  //стандарт для разделения на разряды без деления
  d1= t >> 4;
  while(d1>=10){d1-=10;d10++;}
  dd = (t&15 *10)>>4;
 
 //курсор в 1 строку второй символ см. доки
 lcdCmd(0x80 + 1);
 
 lcdDate('0'+d10);
 lcdDate('0'+d1 );
 lcdDate('.');
 lcdDate('0'+dd);
}
}

 

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

в попытке найти нормальный I2C для тиньки я перерыл много мусора в сети. Пришлось писать. Это точно компилируется и работает в обычном IDE и без напильника. И Даллас работает. Если памяти, как 85-ой, то, думаю, можно уже и стандарным пользоваться. Мне было просто интересно, как задачка, уложиться в Тиньку и с Далласом и с экраном и с И2Ц.

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Никому вроде не нужно... ну да ладно.

В коде есть ошибки. Я RTC DS3231 к тиньке приделал - вылезли ошибки в библиотеке, которые не мешали работать дисплею. Но не давали читать из часов.

Все равно SoftI2C-master - лучше моей. У меня, если в размер вписываться, то все зашитные проверки на "медленного слейва" нужно отключать.

выложу правленную. Но та - на асме, а мою можно легко перенести на любой контроллер.



#define _NOP() asm volatile("nop")

// delay() для тиньки и свой нормальный, а delayMicroseconds() дурной
//поэтому свой нужен

//а вот глобального такого дефайна может и не быть, как ни странно, так для страховки завел
#define F_CPU 4800000UL
#define LOOP_CYCLES 8
#define us(num) (num/(LOOP_CYCLES*(1/(F_CPU/1000000.0))))

inline __attribute__((gnu_inline)) void asm_delay(uint16_t delay){
  uint16_t u=us(delay);
do _NOP(); while(delay--);
}

#define wdelay_us(x)  asm_delay(us(x))
#define wdelay(x) delay(x)


/*****************************************************/
//дальше мелкий вариант i2c на любых ногах
//если работать через функции (закоментировано) то будет переносимость хоть куда

#define IICR  1
#define IICW  0
// на 100КГц примерно по 4 мкс нужно держать уровни SCL - со скоростью сами экспериментируйте, мне не нужно было
#define I2CDelay()  wdelay_us(5)
#define SDA_Pin   0
#define SCL_Pin   1

/*
#define SDA_In()    digitalRead(SDA_Pin)
#define SCL_In()    digitalRead(SCL_Pin)

     void SDA_Hi()  { digitalWrite(SDA_Pin, HIGH); pinMode(SDA_Pin,  INPUT);}
     void SDA_Lo()  { digitalWrite(SDA_Pin, LOW ); pinMode(SDA_Pin, OUTPUT);}
     void SCL_Hi()  { digitalWrite(SCL_Pin, HIGH); pinMode(SCL_Pin,  INPUT);}
     void SCL_Lo()  { digitalWrite(SCL_Pin, LOW ); pinMode(SCL_Pin, OUTPUT);}
*/
#define SDA_In()    (PINB & 0B00000001)
#define SCL_In()    (PINB & 0B00000010)

     inline void SDA_Hi()  { PORTB |= 0B00000001; DDRB &= 0B11111110;}
     inline void SDA_Lo()  { PORTB &= 0B11111110; DDRB |= 0B00000001;}
     inline void SCL_Hi()  { PORTB |= 0B00000010; DDRB &= 0B11111101;}
     inline void SCL_Lo()  { PORTB &= 0B11111101; DDRB |= 0B00000010;}

void I2CInit (void)
{
    SDA_Hi();
    SCL_Hi();
}

void I2CStart (void)
{
  SCL_Hi();
  //while (!SCL_In());
  I2CDelay();
  SDA_Lo();
  I2CDelay();
  SCL_Lo();  
  
}
 
void I2CStop (void)
{
  SCL_Lo();
  SDA_Lo();
  I2CDelay();
  SCL_Hi();
  //while(!SCL_In());
  I2CDelay();
  SDA_Hi();
  I2CDelay();
}

boolean I2CWrite(byte b)
{
  byte i = 1<<7;
  boolean ack=0;

  while(i)
    {
      //I2CDelay();
      if (b & i) SDA_Hi(); else SDA_Lo();
      I2CDelay();
      SCL_Hi();
      I2CDelay();
      SCL_Lo();
      
      i>>=1; 
    }
  SDA_Hi();
  I2CDelay();
  SCL_Hi();
 // while(!SCL_In());

  if ( SDA_In()==0 ) ack = 1;
  I2CDelay();
  SCL_Lo();
  SDA_Hi();
  return ack;
}

byte I2CRead(boolean ack)
{
  byte i=8;
  byte b=0;
  
  while(i--)
  {
   b <<= 1;
   SCL_Lo();
   SDA_Hi();
   I2CDelay();
   SCL_Hi();
   //while(!SCL_In());
   if (SDA_In()) b |= 1;
   
   I2CDelay();
   SCL_Lo();
  }
  if (ack) SDA_Lo();
  else SDA_Hi();
  I2CDelay();
  SCL_Hi();
  //while(!SCL_In());
  I2CDelay();
  SCL_Lo();
  return (b);
}

 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Собрал простое для повторения устройство

В двух словах, с хорошей точностью показывает уровень заряда li-ion АКБ, имеет девять режимов индикации.

Сделал для себя несколько.

Более подробно текст и видео здесь.

nik182
Offline
Зарегистрирован: 04.05.2015

wdrakula пишет:

Никому вроде не нужно... ну да ладно.


Попробовал часы на 25 тиньке. На 200 байт меньше, чем на TWI. Отлично. Теперь есть возможность температуру раз в минуту выводить. А то часы с будильником на DS3231 и семисегментом индикаторе занимали всю память. За байты бороться пришлось.

Yusupoff
Offline
Зарегистрирован: 14.09.2016

Здравсвуйте!

Есть Tiny с кодом на поливку растений с простым условием и с паузой 10мин

Хотелось бы не ставить на паузу а отправлять в сон  на 20 и более минут

Как это организовать?

 

 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Yusupoff пишет:

Здравсвуйте!

Есть Tiny с кодом на поливку растений с простым условием и с паузой 10мин

Хотелось бы не ставить на паузу а отправлять в сон  на 20 и более минут

Как это организовать?

Привет.

Есть подробные ролики на ютюб.

Там парень сделал на тини13 устройство для полива растений,

оно работает на тини13 от батарейки СR2032 около 5лет.

Ищите через поиск ютюба.

pittyalex
Offline
Зарегистрирован: 09.11.2016

Господа, смотрел-смотрел, и всё-таки не выдержал В) Даже зарегистрировался... В общем, смотрите:

1 DDRB |= (1<<PB2);
2 DDRB |= (1<<PB1);
3 DDRB |= (1<<PB0);
4 DDRB &= ~(1<<PB4);
5 DDRB &= ~(1<<PB3);
6  
7 PORTB &= ~(1<<PB2);
8 PORTB |= (1<<PB1);
9 PORTB &= ~(1<<PB0);

Вот такую хрень можно заменить всего на 2 команды.

DDRB = 0b00000111; //Я так понимаю, Вы хотели поставить регистр направления PB0, PB1, PB2 в единицу

PORTB = 0b00000010; // PB0 = 0, PB1=1, PB2 = 0;

strarbit
Offline
Зарегистрирован: 12.06.2016

Нельзя заменить на такую хрень
Потому что нужно изменить конкретный разряд  порта, не изменяя остальные, а не переписывать весь порт
 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

pittyalex пишет:

Господа, смотрел-смотрел, и всё-таки не выдержал В) Даже зарегистрировался... В общем, смотрите:

DDRB |= (1<<PB2);
DDRB |= (1<<PB1);
DDRB |= (1<<PB0);
DDRB &= ~(1<<PB4);
DDRB &= ~(1<<PB3);
 
PORTB &= ~(1<<PB2);
PORTB |= (1<<PB1);
PORTB &= ~(1<<PB0);

Вот такую хрень можно заменить всего на 2 команды.

DDRB = 0b00000111; //Я так понимаю, Вы хотели поставить регистр направления PB0, PB1, PB2 в единицу

PORTB = 0b00000010; // PB0 = 0, PB1=1, PB2 = 0;

Это не хрень а операции с отдельно взятым битом, то что вы предлагаете настраивает весь порт сразу и это не всегда нужно.

Допустим если в коде предусмотрено изменение выводов кнопок через

#define key  PB2  //вход кнопки

DDRB |= (1<< key );

Хотели поумничать,  а не получилось!)

nik182
Offline
Зарегистрирован: 04.05.2015

Конечно можно. Если вам нужно один раз настроить порт и прописать значения.

pittyalex
Offline
Зарегистрирован: 09.11.2016

bodriy2014 пишет:

pittyalex пишет:

Господа, смотрел-смотрел, и всё-таки не выдержал В) Даже зарегистрировался... В общем, смотрите:

DDRB |= (1<<PB2);
DDRB |= (1<<PB1);
DDRB |= (1<<PB0);
DDRB &= ~(1<<PB4);
DDRB &= ~(1<<PB3);
 
PORTB &= ~(1<<PB2);
PORTB |= (1<<PB1);
PORTB &= ~(1<<PB0);

Вот такую хрень можно заменить всего на 2 команды.

DDRB = 0b00000111; //Я так понимаю, Вы хотели поставить регистр направления PB0, PB1, PB2 в единицу

PORTB = 0b00000010; // PB0 = 0, PB1=1, PB2 = 0;

Это не хрень а операции с отдельно взятым битом, то что вы предлагаете настраивает весь порт сразу и это не всегда нужно.

Допустим если в коде предусмотрено изменение выводов кнопок через

#define key  PB2  //вход кнопки

DDRB |= (1<< key );

Хотели поумничать,  а не получилось!)


Вот не хочется флуд разводить, но не могу удержаться: как раз это у вас на получилось поумничать. Рекомендация была дана на конкретный кусок кода, где она даёт достаточно большой выигрыш как во флеше, так и в быстродействии. В зависимости от настроек компилятора, приведенный мной в самом начале код может вылиться в от 18 до 40 команд, приведенный мной код дает 4 или 5 команд.

pittyalex
Offline
Зарегистрирован: 09.11.2016

bodriy2014 пишет:

pittyalex пишет:

Господа, смотрел-смотрел, и всё-таки не выдержал В) Даже зарегистрировался... В общем, смотрите:

DDRB |= (1<<PB2);
DDRB |= (1<<PB1);
DDRB |= (1<<PB0);
DDRB &= ~(1<<PB4);
DDRB &= ~(1<<PB3);
 
PORTB &= ~(1<<PB2);
PORTB |= (1<<PB1);
PORTB &= ~(1<<PB0);

Вот такую хрень можно заменить всего на 2 команды.

DDRB = 0b00000111; //Я так понимаю, Вы хотели поставить регистр направления PB0, PB1, PB2 в единицу

PORTB = 0b00000010; // PB0 = 0, PB1=1, PB2 = 0;

Это не хрень а операции с отдельно взятым битом, то что вы предлагаете настраивает весь порт сразу и это не всегда нужно.

Допустим если в коде предусмотрено изменение выводов кнопок через

#define key  PB2  //вход кнопки

DDRB |= (1<< key );

Хотели поумничать,  а не получилось!)


Вот не хочется флуд разводить, но не могу удержаться: как раз это у вас на получилось поумничать. Рекомендация была дана на конкретный кусок кода, где она даёт достаточно большой выигрыш как во флеше, так и в быстродействии. В зависимости от настроек компилятора, приведенный мной в самом начале код может вылиться в от 18 до 40 команд, приведенный мной код дает 4 или 5 команд.

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

pittyalex пишет:

Вот не хочется флуд разводить, но не могу удержаться: как раз это у вас на получилось поумничать. Рекомендация была дана на конкретный кусок кода, где она даёт достаточно большой выигрыш как во флеше, так и в быстродействии. В зависимости от настроек компилятора, приведенный мной в самом начале код может вылиться в от 18 до 40 команд, приведенный мной код дает 4 или 5 команд.

Вы почему решили что люди которые используют

  DDRB |= (1 << PB0);
  //Вместо
  pinMode(PB0, OUTPUT);
  //не знают что можно прописать весь порт сразу?
  DDRB = 0b00000001;

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

Вы говорите что аж не стерпели такого варварства и зарегистрировались на форуме чтоб просветить несчастных.

Здесь хватает действительно умных людей, а не умников, и есть кому просветить.

Можете смело проходить мимо.

 

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Yusupoff пишет:

Здравсвуйте!

Есть Tiny с кодом на поливку растений с простым условием и с паузой 10мин

Хотелось бы не ставить на паузу а отправлять в сон  на 20 и более минут

Как это организовать?

Можно загнать в глубокий сон, но на 20мин без внешнего прерывания не получится.

Без внешнего прерывания можно максимум на 8с в сон, с пробуждением по сторожевому таймеру.

pittyalex
Offline
Зарегистрирован: 09.11.2016

bodriy2014 пишет:

pittyalex пишет:

Вот не хочется флуд разводить, но не могу удержаться: как раз это у вас на получилось поумничать. Рекомендация была дана на конкретный кусок кода, где она даёт достаточно большой выигрыш как во флеше, так и в быстродействии. В зависимости от настроек компилятора, приведенный мной в самом начале код может вылиться в от 18 до 40 команд, приведенный мной код дает 4 или 5 команд.

Вы почему решили что люди которые используют

  DDRB |= (1 << PB0);
  //Вместо
  pinMode(PB0, OUTPUT);
  //не знают что можно прописать весь порт сразу?
  DDRB = 0b00000001;

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

Вы говорите что аж не стерпели такого варварства и зарегистрировались на форуме чтоб просветить несчастных.

Здесь хватает действительно умных людей, а не умников, и есть кому просветить.

Можете смело проходить мимо.

 

Вот я не понимаю: никому не грубил, ничьё достоинство не унижал, посоветовал, как сделать лучше В КОНКРЕТНОМ СЛУЧАЕ, где для человека, который, как вы выразились "Пишет на ардуино", дают совет по использованию прямого доступа к портам (а ведь тот, кому советуют, не знает этого, а тот, кто советует, прекрасно понимает, что он советует и мог бы сразу написать маску для тех пинов, которые нужны, можно было написать с помощью битовой маски с именованием пинов, это было бы более красиво).

Просто когда в тини13 запихивают ардуину, имеет смысл бороться за каждый байт и каждый цикл программы. И лучше уж сразу людям, хоть по немного, но показывать направление движения.

Ещё раз сделаю ремарку, чтобы расставить точки: такой подход - это общее место при инициализации различных аппаратных устройств, имеющих множетсво разных бит в регистрах конфигурации. Вместо того, чтобы дёргать каждый бит, имеет смысл заранее сформировать (при компиляции) байт (слово) регистра, и потом просто записать его.

Прошу прощения, если кого-то своими словами обидел, истинно - не хотел.

 

P.S. Господин Бодрый, к Вашему вопросу насчёт "//не знают, что можно прописать весь порт сразу?", отвечу, что люди, которые об этом не знают, берут кусочки кода, которые им рекомендуют люди, которые об этом знают, и потом у них даже мысли не возникает, что можно сделать немного проще. 

pittyalex
Offline
Зарегистрирован: 09.11.2016

Yusupoff пишет:

Здравсвуйте!

Есть Tiny с кодом на поливку растений с простым условием и с паузой 10мин

Хотелось бы не ставить на паузу а отправлять в сон  на 20 и более минут

Как это организовать?

Как уже говорил тов. Бодрый, в PD можно только на 8 с. Поэтому 3 решения:

1. Внешняя времязадающая цепь на просыпание (с любым вам удобным временем) - не кузяво.

2. Переводим тиню в самый медленный режим (тактирование от 128 кГц с прескаллером на 256), засыпаем в PD и по просыпанию через каждые 8 с считаем какой-нибудь счётчик, если время не вышло - сразу опять засыпаем. На всё это уйдет совсем мало времени, а учитывая. что в режиме тактирования от 0,5 кГц потребление даже в активном режиме будет при 3.3 В меньше 15 мкА, а в PD режиме при таком напряжении будет 4-5 мкА. Т.е. разница не такая уж и большая, учитывая, что просыпаться он будет на совсем короткое время.

3. Отключаем WDT, переводим опять на самую низкую частоту тиню, выдержку отсчитываем таймером 0 (макс. время, если я не обсчитался, получается 524 с. Не густо, но уже не 8 с. На время выдержки времени переводим в режим Idle. Просыпаемся по переполнению таймера Т0. Потребление в таком режиме будет, если верить даташиту, 10-15 мкА. От батареи CR2032 без других потребителей в таком режиме должно проработать почти 2 года.

Мне лично нравится режим 2.

Кроме того, если есть свободные ноги у Тини, и есть ещё другая окружающая схема, которая может жрать мощность, имеет смысл эту схему отключить с помощью транзистора, а напряжение питания тини понизить до 1.8 в с помощью диодов.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

Удалось упаковать код для работы DHT11 + TM1637 в 1 килобайт и заставить работать всё на AtTiny13. Вдруг, кому пригодится. Видео здесь https://youtu.be/EhzBILnumkk. На видео третье число - это контрольная сумма. После записи видео код немного усовершенствовал. Сильно не ругайтесь, я всего месяц практикую с программированием, с тех пор, как ардуинку приобрел))

#define F_CPU 1200000LU
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h> 

unsigned char word_dht = 0x00;
unsigned char time_bit[40];
unsigned char data_dht[5];
unsigned char bit_dht;


#define Clkpin 3 //Clkpin TM1637
#define Datapin 2 // Datapin TM1637
#define PIN_DHT 0 //Пин датчика DHT

#define DispPort PORTB // обзываем порт

#define  BRIGHT_LCD 7  //Яркость дисплея от 0 до 7
		
		unsigned char _PointFlag; 	//_PointFlag=1:the clock point on
		unsigned char _DispType;
		unsigned char DecPoint;
		unsigned char BlankingFlag;
	
		
static unsigned char TubeTab[10] = {0x3f,0x06,0x5b,0x4f,// знакогенератор
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f};//,0x77,0x7c,
                           //0x39,0x5e,0x79,0x71,
                          // 0x40,0x00};//0~9,A,b,C,d,E,F,"-"," "  

void TM1637_writeByte(char wr_data)// служебная функция записи данных по протоколу I2C, с подтверждением (ACK)
{
  unsigned char i;
    for(i=0;i<8;i++)        
  {
   DispPort &= ~(1<<Clkpin);
    if(wr_data & 0x01)
	{ DispPort |= 1<<Datapin;}
    else {DispPort &= ~(1<<Datapin);}
	_delay_us(3);
    wr_data = wr_data>>1;      
    DispPort |= 1<<Clkpin;
	_delay_us(3);  
  }  
 
  DispPort &= ~(1<<Clkpin);
  _delay_us(5);
  DDRB &= ~(1<<Datapin);// если поменяете порт на какой-то другой кроме DispPort, то тут тоже все DDRB на другие DDRx менять надо будет
  while((PINB & (1<<Datapin))); 
  DDRB |= (1<<Datapin);
  DispPort |= 1<<Clkpin;
  _delay_us(2);
  DispPort &= ~(1<<Clkpin);  
}

void TM1637_start(void) // просто функция "старт" для протокола I2C
{
   DispPort |= 1<<Clkpin; 
   DispPort |= 1<<Datapin;
 _delay_us(2);
  DispPort &= ~(1<<Datapin); 
} 

void TM1637_stop(void) // просто функция "стоп" для протокола I2C
{
  DispPort &= ~(1<<Clkpin);
 _delay_us(2);
  DispPort &= ~(1<<Datapin);
_delay_us(2);
  DispPort |= 1<<Clkpin;;
_delay_us(2);
  DispPort |= 1<<Datapin;
}


void TM1637_init()// Инициализируем дисплей. Как оказалось, можно удалить из этого блока стандартной библиотеки практически всё, кроме инициализации пинов.
{
	DDRB |= (1<<Clkpin) | (1<<Datapin);
}

//---------------------------------------------------------------------
//Здесь код для датчика DHT11. Писал полностью сам.

void start_tmr_us()
{
TCNT0 = 0x00;
TCCR0B = 0x01; //Запускаем таймер0 с частотой 1,2 Мгц
}

void start_dht()                //Отправляем приветствие датчику
{
DDRB |= (1 << PIN_DHT);
DispPort |= (1 << PIN_DHT);
DispPort &= ~(1 << PIN_DHT);
_delay_ms(18);
DDRB &= ~(1 << PIN_DHT);
DispPort |= (1 << PIN_DHT);
while(PINB & (1 << PIN_DHT)){}
while(~PINB & (1 << PIN_DHT)){}
while(PINB & (1 << PIN_DHT)){}

}

void get_data()                            //Получаем 40 бит от датчика и записываем в массив
{
for(bit_dht = 0; bit_dht < 40; bit_dht++)
{
while(~PINB & (1 << PIN_DHT)){}
start_tmr_us();
while(PINB & (1 << PIN_DHT)){}
time_bit[bit_dht] = TCNT0;
}
}

void decoder_bit(){
unsigned char bit_number = 1;
unsigned char word_number = 0;
for(bit_dht = 0; bit_dht < 40; bit_dht++){  //дербаним наш массив из 40 бит (5 байтов), в котором записана длительность каждого полученного  бита

if(time_bit[bit_dht] > 50)                //Если длительность бита больше 28 мкс,
{
word_dht = word_dht << 1;            //сдвигаем байт влево и записываем в младший разряд 1
word_dht |= (1 << 0);
}else
{
word_dht = word_dht << 1;        //Если меньше 28 мкс, сдвигаем влево байт и записываем 0
word_dht &= ~(1 << 0);
}

if(bit_number == 8){                     //Если имеем дело с восьмым битом, записываем полученный байт в массив
data_dht[word_number] = word_dht;
word_number += 1;
bit_number = 0;       
}
bit_number +=1;
}
}



ISR (WDT_vect){
TM1637_writeByte(0x40);    //Выводим на дисплей Err1
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(0x79);
TM1637_writeByte(0x50);
TM1637_writeByte(0x50);
TM1637_writeByte(0x06);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop();
}




int main(void)
{
wdt_reset();            //Запускаем вотч дог
wdt_enable(WDTO_4S);
WDTCR |= (1 << WDTIE);
sei();
TM1637_init();
_delay_ms(500);  //Зачем-то тупим немного. Иначе, вроде как, дисплей может не зажечься.
 
while(1)
{
start_dht();                         
get_data();
decoder_bit();
if((data_dht[0] + data_dht[1] + data_dht[2] + data_dht[3]) != data_dht[4])
{
	TM1637_writeByte(0x40);    //Выводим на дисплей Err0
	TM1637_stop();
	TM1637_start();
	TM1637_writeByte(0xC0);
	TM1637_writeByte(0x79);
	TM1637_writeByte(0x50);
	TM1637_writeByte(0x50);
	TM1637_writeByte(0x3f);
	TM1637_stop();
	TM1637_start();
	TM1637_writeByte(0x8F);
	TM1637_stop();
	_delay_ms(3500);
	wdt_reset();
	_delay_ms(3500);
	wdt_reset();	
}

TM1637_start();                     //Выводим на дисплей влажность.  
TM1637_writeByte(0x40);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(0x76);
TM1637_writeByte(0x00);
TM1637_writeByte(TubeTab[(data_dht[0] / 10) % 10]);
TM1637_writeByte(TubeTab[data_dht[0] % 10]);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop();
_delay_ms(2000);
wdt_reset();

TM1637_start();                                    //Выводим на дисплей температуру
TM1637_writeByte(0x40);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(TubeTab[(data_dht[2] / 10) % 10]);
TM1637_writeByte(TubeTab[data_dht[2] % 10]);
TM1637_writeByte(0x63);
TM1637_writeByte(0x39);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop(); 
_delay_ms(2000);
wdt_reset();
}
}

 

Joiner
Offline
Зарегистрирован: 04.09.2014

Krendelyok пишет:

Удалось......

Класс!!! Завидую...Вот бы мне так уметь.

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Krendelyok пишет:

....Сильно не ругайтесь, я всего месяц практикую с программированием, с тех пор, как ардуинку приобрел))

Отличный результат!

Многи и через год копирование чужих кусков кода такое не напишут.

#define F_CPU 1200000LU
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/wdt.h> 

unsigned char word_dht = 0x00;
unsigned char time_bit[40];
unsigned char data_dht[5];
unsigned char bit_dht;


#define Clkpin 3 //Clkpin TM1637
#define Datapin 2 // Datapin TM1637
#define PIN_DHT 0 //Пин датчика DHT

#define DispPort PORTB // обзываем порт

#define  BRIGHT_LCD 7  //Яркость дисплея от 0 до 7
		
		unsigned char _PointFlag; 	//_PointFlag=1:the clock point on
		unsigned char _DispType;
		unsigned char DecPoint;
		unsigned char BlankingFlag;
	
		
static unsigned char TubeTab[10] = {0x3f,0x06,0x5b,0x4f,// знакогенератор
                           0x66,0x6d,0x7d,0x07,
                           0x7f,0x6f};//,0x77,0x7c,
                           //0x39,0x5e,0x79,0x71,
                          // 0x40,0x00};//0~9,A,b,C,d,E,F,"-"," "  

void TM1637_writeByte(char wr_data)// служебная функция записи данных по протоколу I2C, с подтверждением (ACK)
{
  unsigned char i;
    for(i=0;i<8;i++)        
  {
   DispPort &= ~(1<<Clkpin);
    if(wr_data & 0x01)
	{ DispPort |= 1<<Datapin;}
    else {DispPort &= ~(1<<Datapin);}
	_delay_us(3);
    wr_data = wr_data>>1;      
    DispPort |= 1<<Clkpin;
	_delay_us(3);  
  }  
 
  DispPort &= ~(1<<Clkpin);
  _delay_us(5);
  DDRB &= ~(1<<Datapin);// если поменяете порт на какой-то другой кроме DispPort, то тут тоже все DDRB на другие DDRx менять надо будет
  while((PINB & (1<<Datapin))); 
  DDRB |= (1<<Datapin);
  DispPort |= 1<<Clkpin;
  _delay_us(2);
  DispPort &= ~(1<<Clkpin);  
}

void TM1637_start(void) // просто функция "старт" для протокола I2C
{
   DispPort |= 1<<Clkpin; 
   DispPort |= 1<<Datapin;
 _delay_us(2);
  DispPort &= ~(1<<Datapin); 
} 

void TM1637_stop(void) // просто функция "стоп" для протокола I2C
{
  DispPort &= ~(1<<Clkpin);
 _delay_us(2);
  DispPort &= ~(1<<Datapin);
_delay_us(2);
  DispPort |= 1<<Clkpin;;
_delay_us(2);
  DispPort |= 1<<Datapin;
}


void TM1637_init()// Инициализируем дисплей. Как оказалось, можно удалить из этого блока стандартной библиотеки практически всё, кроме инициализации пинов.
{
	DDRB |= (1<<Clkpin) | (1<<Datapin);
}

//---------------------------------------------------------------------
//Здесь код для датчика DHT11. Писал полностью сам.

void start_tmr_us()
{
TCNT0 = 0x00;
TCCR0B = 0x01; //Запускаем таймер0 с частотой 1,2 Мгц
}

void start_dht()                //Отправляем приветствие датчику
{
DDRB |= (1 << PIN_DHT);
DispPort |= (1 << PIN_DHT);
DispPort &= ~(1 << PIN_DHT);
_delay_ms(18);
DDRB &= ~(1 << PIN_DHT);
DispPort |= (1 << PIN_DHT);
while(PINB & (1 << PIN_DHT)){}
while(~PINB & (1 << PIN_DHT)){}
while(PINB & (1 << PIN_DHT)){}

}

void get_data()                            //Получаем 40 бит от датчика и записываем в массив
{
for(bit_dht = 0; bit_dht < 40; bit_dht++)
{
while(~PINB & (1 << PIN_DHT)){}
start_tmr_us();
while(PINB & (1 << PIN_DHT)){}
time_bit[bit_dht] = TCNT0;
}
}

void decoder_bit(){
unsigned char bit_number = 1;
unsigned char word_number = 0;
for(bit_dht = 0; bit_dht < 40; bit_dht++){  //дербаним наш массив из 40 бит (5 байтов), в котором записана длительность каждого полученного  бита

if(time_bit[bit_dht] > 50)                //Если длительность бита больше 28 мкс,
{
word_dht = word_dht << 1;            //сдвигаем байт влево и записываем в младший разряд 1
word_dht |= (1 << 0);
}else
{
word_dht = word_dht << 1;        //Если меньше 28 мкс, сдвигаем влево байт и записываем 0
word_dht &= ~(1 << 0);
}

if(bit_number == 8){                     //Если имеем дело с восьмым битом, записываем полученный байт в массив
data_dht[word_number] = word_dht;
word_number += 1;
bit_number = 0;       
}
bit_number +=1;
}
}



ISR (WDT_vect){
TM1637_writeByte(0x40);    //Выводим на дисплей Err1
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(0x79);
TM1637_writeByte(0x50);
TM1637_writeByte(0x50);
TM1637_writeByte(0x06);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop();
}




int main(void)
{
wdt_reset();            //Запускаем вотч дог
wdt_enable(WDTO_4S);
WDTCR |= (1 << WDTIE);
sei();
TM1637_init();
_delay_ms(500);  //Зачем-то тупим немного. Иначе, вроде как, дисплей может не зажечься.
 
while(1)
{
start_dht();                         
get_data();
decoder_bit();
if((data_dht[0] + data_dht[1] + data_dht[2] + data_dht[3]) != data_dht[4])
{
	TM1637_writeByte(0x40);    //Выводим на дисплей Err0
	TM1637_stop();
	TM1637_start();
	TM1637_writeByte(0xC0);
	TM1637_writeByte(0x79);
	TM1637_writeByte(0x50);
	TM1637_writeByte(0x50);
	TM1637_writeByte(0x3f);
	TM1637_stop();
	TM1637_start();
	TM1637_writeByte(0x8F);
	TM1637_stop();
	_delay_ms(3500);
	wdt_reset();
	_delay_ms(3500);
	wdt_reset();	
}

TM1637_start();                     //Выводим на дисплей влажность.  
TM1637_writeByte(0x40);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(0x76);
TM1637_writeByte(0x00);
TM1637_writeByte(TubeTab[(data_dht[0] / 10) % 10]);
TM1637_writeByte(TubeTab[data_dht[0] % 10]);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop();
_delay_ms(2000);
wdt_reset();

TM1637_start();                                    //Выводим на дисплей температуру
TM1637_writeByte(0x40);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0xC0);
TM1637_writeByte(TubeTab[(data_dht[2] / 10) % 10]);
TM1637_writeByte(TubeTab[data_dht[2] % 10]);
TM1637_writeByte(0x63);
TM1637_writeByte(0x39);
TM1637_stop();
TM1637_start();
TM1637_writeByte(0x8F);
TM1637_stop(); 
_delay_ms(2000);
wdt_reset();
}
}

Ссылочку свою подправьте, точка влезла.

https://youtu.be/EhzBILnumkk

Joiner
Offline
Зарегистрирован: 04.09.2014

Krendelyok пишет:

Удалось .......

Krendelyok, а Вы как изучали, что добились такого понимания? Я вот 2 года изучаю, что-то читаю, а все топчусь на одном месте :(

pittyalex
Offline
Зарегистрирован: 09.11.2016

Молодец. А почему так показания скачут? И влажность и температура. Может имеет смысл сглаживание какое замутить?
Хинт: в авр есть возможность : ногодрыга не прямым обращением в порт (чтение-модификация-запись, минимум на 2 дрыгания 3 команды, если компилятор будет умным), а битбангом через sbi/cbi. Сама команда вроде одно слово, но выполняется все равно за два цикла. Можно несколько байт выкроить флеша. К тому же не используется промежуточный регистр. И еще один трик: если нужно проигнорировать состояние выходного пина, то можно в его разряд записать 1 в регистре PINB и это проинвертирует выход. Всего одна команда.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

Joiner пишет:

Krendelyok пишет:

Удалось .......

Krendelyok, а Вы как изучали, что добились такого понимания? Я вот 2 года изучаю, что-то читаю, а все топчусь на одном месте :(

 

Ну на самом деле теорию я изучал очень давно в институте еще в начале нулевых. )) Немного осталось в памяти двоичной логики. Но на практику у меня тогда тупо не было денег) Компьютеров у нищебродов не было. Программировать желание было большое , а возможности никакой. Потом работа не по профессии. ) Типичная история. А тут чет вспомнил молодость. Сначала решил Джаву поизучать. Но дальше циклов не ушел. Потому что пришла Ардуинка из Китая. Переключился на Си. И затянуло. А тут еще и программатор подвернулся под руку, старенький ChipProg-2. Тоесть кувыряюсь чисто для души. А не ради того, чтоб что-то собрать. Остановился пока на книге Прокопенко В. С. "Программирование микроконтроллеров Atmel  на языке Си". Сухо написана, с грамматическими ошибками, но ёмко)) Если кто посоветует получше книгу - буду рад. Извиняюсь за оффтоп.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

pittyalex пишет:
Молодец. А почему так показания скачут? И влажность и температура. Может имеет смысл сглаживание какое замутить? Хинт: в авр есть возможность : ногодрыга не прямым обращением в порт (чтение-модификация-запись, минимум на 2 дрыгания 3 команды, если компилятор будет умным), а битбангом через sbi/cbi. Сама команда вроде одно слово, но выполняется все равно за два цикла. Можно несколько байт выкроить флеша. К тому же не используется промежуточный регистр. И еще один трик: если нужно проигнорировать состояние выходного пина, то можно в его разряд записать 1 в регистре PINB и это проинвертирует выход. Всего одна команда.

 Я так понимаю, какие-то помехи)) Контрольная сумма в норме. С другим БП прыжки периодически есть, но поменьше. Видимо, микросхема датчика очень критична к питанию. Либо у меня брак. Но, с другой стороны, дома на Ардуино Уно тестировал этот датчик, таких прыжков не было. Спасибо за информацию, буду переваривать.

Joiner
Offline
Зарегистрирован: 04.09.2014

Krendelyok пишет:

..... Остановился пока на книге Прокопенко В. С. "Программирование микроконтроллеров Atmel  на языке Си". Сухо написана, с грамматическими ошибками, но ёмко)) Если кто посоветует получше книгу - буду рад. Извиняюсь за оффтоп.

Спасибо, поищу.

pittyalex
Offline
Зарегистрирован: 09.11.2016

Krendelyok пишет:

pittyalex пишет:
Молодец. А почему так показания скачут? И влажность и температура. Может имеет смысл сглаживание какое замутить? Хинт: в авр есть возможность : ногодрыга не прямым обращением в порт (чтение-модификация-запись, минимум на 2 дрыгания 3 команды, если компилятор будет умным), а битбангом через sbi/cbi. Сама команда вроде одно слово, но выполняется все равно за два цикла. Можно несколько байт выкроить флеша. К тому же не используется промежуточный регистр. И еще один трик: если нужно проигнорировать состояние выходного пина, то можно в его разряд записать 1 в регистре PINB и это проинвертирует выход. Всего одна команда.

 Я так понимаю, какие-то помехи)) Контрольная сумма в норме. С другим БП прыжки периодически есть, но поменьше. Видимо, микросхема датчика очень критична к питанию. Либо у меня брак. Но, с другой стороны, дома на Ардуино Уно тестировал этот датчик, таких прыжков не было. Спасибо за информацию, буду переваривать.

М.б. в моменты индикации из-за разного тока потребления проседает напряжение и из-за этого датчик туфту гонит??

Посмотрел даташит на DHT11. т.к. время установления  датчика влажности 10 с, датчика температуры где-то 20 с, предлагаю с такими же постоянными времени замутить фильтрацию, ато и ещё поболее.

 

Krendelyok
Offline
Зарегистрирован: 05.10.2016

pittyalex пишет:

М.б. в моменты индикации из-за разного тока потребления проседает напряжение и из-за этого датчик туфту гонит??

Как раз наоборот получается. Туфту гонит, когда подключен от БП 12 вольт. А когда от 6 вольт, то меньше туфты)) При этом через преобразователь, который на макетке, от 6 вольт на микросхемах остается что-то около 3 вольт всего (мало ему 6 вольт). От батареек надо запитать))

wdrakula
wdrakula аватар
Онлайн
Зарегистрирован: 15.03.2016

Ткни осликом в питание. возможно помехи. Если нет ослика - то звуковухой и виртуальным ослом (поиск по словам " осцилограф из звуковой карты"). Хотя в БП помехи, скорее всего от 40КГц и выше, звуковуха может не увидеть. Конденсатор на 10-100мкф и 0.1 параллельно... ну типа стандарт такой.

Еще вариант добавить дроссель - примерно 100 витков от ненужного старого трансформатора (примерно 0.1 кв.мм) на резистор 0.125, номиналом в 100К-500К. Если есть покупные, то порядка 20-40 мкГн. 

Чтобы помеха от датчика ниже была, можно дата-пин от DHT подтянуть к питанию не 10К а меньше. Безболезненно до 2К уменьшать можно. (это увеличивает ток в линии)

Если нужны будут средние, то спроси тут, я покажу несколько типичных приемов, штоп велосипед не изобретать.

 

pittyalex
Offline
Зарегистрирован: 09.11.2016

а схема всей конструкции есть? Конденсаторы везде стоят?

Кстати, у тебя в инициализации датчик пробуждается через 500 мс, в даташите сказано, что ему надо " 1 секунду после подачи питания для того, чтобы очухаться". Попробуй эту выдержку сделай.

pittyalex
Offline
Зарегистрирован: 09.11.2016

dimax пишет:

zilibob4ik, да, я забыл. Это же в ардуиновской функции analogWrite() сделано было.. Как вариант можно просто ивертировать шим. При OCR0A=255 будет чистый LOW. При OCR0A=0 будет HIGH с тонкими (1/256) выпадами к нолю.

void setup() {  
DDRB|= 1 << DDB0;  //напрвление: 0 - это вход, 1 - это выход
PORTB|= 1<<PB2; // подтяжка порта B2 непонятно для чего
TCCR0A |= (1 << COM0A1)|(1 << COM0A0)| (1 << WGM00); // PWM Phase Correct (Mode 0)
TCCR0B = (1 << CS02); // делитель на 256 (при тактовой 9,6  ШИМ 75Герц )             
OCR0A=64; // начальная скважность
} 

void loop(){
// тут какая-то программа меняющая OCR0A
}

Можно использовать стандартную ардуиновскую функцию, но командой из 5 строки в сетапе поменять частоту шима на нужную.

Странно, понимаю, что это было очень давно, но может актуально.

В режиме 1 или 5 (Phase correct) по идее не должно быть спайков в начале цикла, вот цитата из даташита:

The extreme values for the OCR0A Register represent special cases when generating a PWM
waveform output in the phase correct PWM mode. If the OCR0A is set equal to BOTTOM, the
output will be continuously low and if set equal to MAX the output will be continuously high for
non-inverted PWM mode. For inverted PWM the output will have the opposite logic values.
 
Там дальше есть исключение, может быть на него Вы тогда и нарвались?
At the very start of period 2 in Figure 11-7 on page 67 OCn has a transition from high to low
even though there is no Compare Match. The point of this transition is to guarantee symmetry
around BOTTOM. There are two cases that give a transition without Compare Match.
• OCR0A changes its value from MAX, like in Figure 11-7 on page 67. When the OCR0A value
is MAX the OCn pin value is the same as the result of a down-counting Compare Match. To
ensure symmetry around BOTTOM the OCn value at MAX must correspond to the result of
an up-counting Compare Match.
• The timer starts counting from a value higher than the one in OCR0A, and for that reason
misses the Compare Match and hence the OCn change that would have happened on the
way up.
Но больше мне кажется, что у господина Зилибобчика был выбран не режим 1 или 5, а либо фаст ШИМ, или ещё что-то.

 

Krendelyok
Offline
Зарегистрирован: 05.10.2016

pittyalex пишет:

а схема всей конструкции есть? Конденсаторы везде стоят?

Кстати, у тебя в инициализации датчик пробуждается через 500 мс, в даташите сказано, что ему надо " 1 секунду после подачи питания для того, чтобы очухаться". Попробуй эту выдержку сделай.

Да какая тут схема. Тут минимализм. По питанию стоят конденсаторы в БП и на платке, которая на макетке понижает напряжение до 5 вольт. Я как-то не запариваюсь на счет показаний DHT11. Это ж игрушка. Надо хотя бы DHT22 для чего то серьезного. Или я неправ? В коде задержку 500 мс оставил именно для дисплея. Он, зараза, при запуске, если уменьшить это время, при первой отправке данных не отправляет ACK, контроллер зависает в while и уходит на обработку прерывания ватч дога. В результате увидим сначала Err1, потом влажность и температуру. Причем, в даташите на дисплей я ничего об этой задержке не нашел. Ткните носом, а то у меня с английским туго.  Можно, наверное меньше 500 мс оставить, но на 100 уже не работает. Я из-за этой проблемы даже хотел отказаться от своей идеи записать код в тиньку13) Пока не разгадал, почему дисплей не стартует)

Krendelyok
Offline
Зарегистрирован: 05.10.2016

wdrakula пишет:

Чтобы помеха от датчика ниже была, можно дата-пин от DHT подтянуть к питанию не 10К а меньше. Безболезненно до 2К уменьшать можно. (это увеличивает ток в линии)

Ну это , если я правильно понимаю, применительно к тем случаям, когда Контрольная сумма не алё) А тут проблема именно в логике микросхемы датчика, в том, как она обрабатывает параметры тока непосредственно на измерительном элементе. Данные и Контрольная сумма совпадают, тоесть в процессе отправки данных ошибок нет.

pittyalex
Offline
Зарегистрирован: 09.11.2016

Krendelyok пишет:

pittyalex пишет:

а схема всей конструкции есть? Конденсаторы везде стоят?

Кстати, у тебя в инициализации датчик пробуждается через 500 мс, в даташите сказано, что ему надо " 1 секунду после подачи питания для того, чтобы очухаться". Попробуй эту выдержку сделай.

Да какая тут схема. Тут минимализм. По питанию стоят конденсаторы в БП и на платке, которая на макетке понижает напряжение до 5 вольт. Я как-то не запариваюсь на счет показаний DHT11. Это ж игрушка. Надо хотя бы DHT22 для чего то серьезного. Или я неправ? В коде задержку 500 мс оставил именно для дисплея. Он, зараза, при запуске, если уменьшить это время, при первой отправке данных не отправляет ACK, контроллер зависает в while и уходит на обработку прерывания ватч дога. В результате увидим сначала Err1, потом влажность и температуру. Причем, в даташите на дисплей я ничего об этой задержке не нашел. Ткните носом, а то у меня с английским туго.  Можно, наверное меньше 500 мс оставить, но на 100 уже не работает. Я из-за этой проблемы даже хотел отказаться от своей идеи записать код в тиньку13) Пока не разгадал, почему дисплей не стартует)

Наоборот, увеличтье до 1 или даже 2х секунд.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

pittyalex пишет:

Наоборот, увеличтье до 1 или даже 2х секунд.

На видео как раз 2 секунды там) Перед стартом можно заметить.  Но в даташите датчика действительно не рекомендуется запрашивать информацию от датчика втечение первой секунды после подачи питания. И рекомендуется конденсатор 100nF на линии питания датчика.

"4. Power and Pin

DHT11’s power supply is 3-5.5V DC. When power is supplied to the sensor, do not send any instruction to the sensor in within one second in order to pass the unstable status. One capacitor valued 100nF can be added between VDD and GND for power filtering."
 
P.S. Кстати, у меня не получилось заставить работать эту связку на 9,6 Мгц. На 4,8 Мгц - работает. В чем причина - особо не разбирался. Если кто разберется - отпишитесь. Там нужно будет соответствующую частоту для таймера выбрать, чтобы он не успевал переполняться за 70 мкс. И подобрать  число для сравнения в строчке 122.
 
P.S.S Разобрался. Похоже, чтобы на 9,6 Мгц работало, нужно просто микросхему запитать от 3 вольт) Это частный случай?)) В даташите не смог найти ничего про напряжение. При этом дисплей запустился только от 5 вольт (раздельное питание). В строчке 89 нужно записать TCCR0B = 0x02; Больше ничего менять не нужно. 
 
Krendelyok
Offline
Зарегистрирован: 05.10.2016

В общем, любопытно мне стало по поводу "прыгания" показаний температуры. Загрузил этот код, который писал для тиньки, в ардуино UNO. И  чудо, товарищи! На ардуинке нет никаких прыжков. Вопрос: так от чего же прыгают показания, не противореча при этом контрольной сумме? Блок питания отпадает - я пробовал брать питание для тиньки с этой ардуинки. Частота Тиньки никак не меняет ситуацию. Прыжки присутствуют на 1,2 Мгц, 4,8 Мгц, 9,6 Мгц. На досуге припаял конденсатор 100 нФ, как рекомендуют в даташите. Пауза при старте отпадает - в Ардуинке тот же самый код.

pittyalex
Offline
Зарегистрирован: 09.11.2016

Акромя БП у самого "синего моря", т.е. ног контроллера и самого датчика должны присутствовать блокировочные конденсаторы 0.1 - 1 мкФ керамика или тантал с низким ESR. Уже подзабыл, но попробуйте пореже опрашивать датчик.

А насчёт паузы, может быть вы и не правы... вы в ардуину заливали скетч? через Arduino IDE и через бутлоадер? Если да, то там уже идёт пауза в самом бутлоадере, плюс ко всему - старт ардуины выполняется на кварце, а там достаточно длинная выдержка на раскачку кварца... может в этом виде? самому стало интересно.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

pittyalex пишет:
Акромя БП у самого "синего моря", т.е. ног контроллера и самого датчика должны присутствовать блокировочные конденсаторы 0.1 - 1 мкФ керамика или тантал с низким ESR. Уже подзабыл, но попробуйте пореже опрашивать датчик.
Пробовал вплоть до 20 секунд интервалы. Не помогало.

pittyalex пишет:
А насчёт паузы, может быть вы и не правы... вы в ардуину заливали скетч? через Arduino IDE и через бутлоадер? Если да, то там уже идёт пауза в самом бутлоадере, плюс ко всему - старт ардуины выполняется на кварце, а там достаточно длинная выдержка на раскачку кварца... может в этом виде? самому стало интересно.
Пауза же у меня прописана в программе (168 строчка, рекомендую там 1500 мс ставить). В общем, я вчера попробовал подключить датчик от другой линии питания, если можно так сказать. Есть вот такая плата 

На ней отдельно два стаба. Так вот тиньку от одного стаба запитал, датчик - от другого. После этого 15 минут тестировал сборку, скачков не было. Причем, стабильно вёл себя датчик, даже если прикасаться влажным пальцем к его контактам)) В отличие от Ардуинки, там в этом случае Err0 выскакивает (ошибка контрольной суммы). Ну в общем, есть вероятность, что отдельное питание датчика устраняет проблему. сам больше проверить не могу. Так как нечаянно перепутал палярность, и спалил датчик )))) Вот так теперь измерительный элемент выглядит. Пахнет жареным.

Если у кого есть возможность, экспериментируйте, отписывайтесь.