• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Программирование ATTINY2313A-PU в среде Arduino IDE 1.8.2

alexlaw

Member
Мне показалось, что еще один микроконтроллер, например в паре с ESP, не будет лишним.
Поэтому решил разобраться с ATTINY2313A-PU.
Вот, что получилось.
Теперь попробую описать мои шаги к этому.
Скетч чтоб не потерялся
Код:
//http://arduinolearning.com/code/program-attiny2313-arduino.php
//https://blog.3d-logic.com/2015/01/21/arduino-and-the-tm1637-4-digit-seven-segment-display/
const int clock1 = 6;
const int data1 = 7;
                 /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
//uint8_t digits2[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
unsigned long t;
uint8_t minutes1;
uint8_t seconds1;
byte dot = 128;//двоеточие на дисплее индикатора
void setup() {
  // put your setup code here, to run once:
pinMode(clock1, OUTPUT);
pinMode(data1, OUTPUT);
start(clock1,data1);
writeValue(clock1,data1,0x8c);
stop(clock1,data1);
// clear display
write(clock1,data1,0x00, 0x00, 0x00, 0x00);
t=0;
    //запускаем таймер                                                                                                                       
    setupInterrupt();
}

void loop() {
if ((t % 2)==0){
  dot=128;
} else {dot=0;}
if (t==3600){t=0;}
minutes1 = (byte)((t / 60) % 60);
seconds1 = (byte)(t % 60);
write(clock1,data1,digits1[seconds1 % 10],digits1[seconds1 / 10] | dot,digits1[minutes1 % 10],digits1 [minutes1 / 10]);
delay(5);

}

void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}

void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}


void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}

bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
void setupInterrupt()
{
/*В состав таймера/счетчика входят следующие регистры ввода/вывода:
16битный счетный регистр TCNT1;
16битный регистр захвата ICR1;
два 16битных регистра сравнения — OCR1A и OCR1B;
три 8битных регистра управления — TCCR1A, TCCR1B и TCCR1C.
Каждый из 16битных регистров физически размещается в двух регист
рах ввода/вывода, названия которых получаются добавлением к названию
регистра  буквы  «H»  (старший  байт)  и  «L»  (младший  байт).  Счетный
регистр таймера/счетчика T1 TCNT1, например, размещается в регистрах
TCNT1H:TCNT1L.*/
 
//Разрешение прерывания осуществляется установкой в 1 бита TOIE1
//TIMSK - регистр маски прерываний
  TIMSK &= ~(1 << TOIE1);// Clear bit
//OCIE1B - Флаг разрешения прерывания по совпадению "В" Т1
//OCIE1A - Флаг разрешения прерывания по совпадению "А" Т1
  TIMSK &= ~((1 << OCIE1A) | (1 << OCIE1B));// Clear bit
//Режим Normal
//Это  наиболее  простой  режим  работы  16битного  таймера/счетчика.
//В данном режиме счетный регистр функционирует как обычный суммирующий счетчик.
  TCCR1A &= ~((1 << WGM11) | (1 << WGM10));
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12));
 
  //Fcpu = 8000000 Гц
  //Период тактового сигнала микроконтроллера Tcpu = 1/Fcpu
  //Период тактового сигнала таймера Т1 равен Tt1 = (1/Fcpu)/k = k/Fcpu
  //256/8000000=0.032 мс
  //Делим требуемый интервал времени (1000 мс) на длительность одного такта таймера
  //1000/0.032=31250
  //2^16 + 1 - 31250 = 34287;
  //Выбор источника тактового сигнала таймера/счетчика T1 clk I/O /256

  //clk I/O
  //TCCR1B |= (1 << CS10);// Set bits
  //TCCR1B &= ~((1 << CS11) | (1 << CS12));// Clear bit

  //clk I/O /8
  //TCCR1B |= (1 << CS11);// Set bits
  //TCCR1B &= ~((1 << CS10) | (1 << CS12));// Clear bit

  //clk I/O /64
  //TCCR1B |= (1 << CS11)  | (1 << CS10); // Set bits
  //TCCR1B &= ~(1 << CS12);           // Clear bit

  //clk I/O /256
  TCCR1B |= (1 << CS12);// Set bits
  TCCR1B &= ~((1 << CS10) | (1 << CS11));// Clear bit

  //clk I/O /1024
  //TCCR1B |= (1 << CS12)  | (1 << CS10); // Set bits
  //TCCR1B &= ~(1 << CS11);           // Clear bit

  /* Save value globally for later reload in ISR */
 TCNT1=34287;
 //Флаг разрешения прерывания по переполнению
 TIMSK |= (1 << TOIE1);// Set bits
 
}
//Install the Interrupt Service Routine (ISR) for Timer1 overflow.
ISR(TIMER1_OVF_vect) {
  TCNT1=34287;
  t++;
}

схема
Схема.png

Исходные данные
  1. ATTINY2313A-PU
  2. WAVGAT ардуино Nano Mini-USB С загрузчика Совместимость Nano 3,0 контроллер CH340 драйвер USB 16 мГц Nano v3.0
  3. TM1637 светодиодный дисплей модуль 7 сегмент 4 биты 0,36
  4. Мини USBISP USBASP (MX-USBISP-V4.00 надпись на плате, процессор - мега88)
  5. Windows 8.1 x64
  6. Arduino IDE 1.8.2
  7. Макетная плата
img1.png
img2.png


Продолжение следует...
 

alexlaw

Member
Переделка китайского USBISP на меге88 в USBASP
Updating firmware on USBASP bought from eBay

Nano ISP
5V ------------ 2
GND ---------10
13 ----------- 7 (SCK)
12 ---------- 9 (MISO)
11 ----------- 1 (MOSI)
10 ----------- 5 (RESET)

Устанавливаем драйвера - USBasp - USB programmer for Atmel AVR controllers - fischl.de
Подключаем USBISP
(у меня определилась как HID устройство, горит красный светодиод) - отключаем

Ставим перемычку UP
Подключаем к макетной плате
img4.png

Cмотрим порт (у меня COM3)
Arduino IDE -Инструменты-Arduino as ISP
Файл-Примеры-ArduinoISP - прошиваем Arduino nano
Командная строка в режиме администратора.
Пробуем прочитать USBISP
Код:
"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c avrisp -P COM3 -b 19200 -p m88 -U flash:r:c:\original_firmware.bin:r
Если да, то шьем.
У меня пошла эта прошивка -
ATmega88.zip
Бросаем прошивку в C:\Program Files (x86)\Arduino\hardware\tools\avr\bin
Набираем команды
Код:
cd "C:\Program Files (x86)\Arduino\hardware\tools\avr\bin"
Код:
avrdude.exe -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c avrisp -P COM3 -b 19200 -p m88 -v -u -U hfuse:w:0xdf:m -U lfuse:w:0xff:m
Код:
avrdude.exe -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c avrisp -P COM3 -b 19200 -p m88 -U flash:w:atmega88.hex
У меня получилось - теперь горит синий светодиод и появилось USBasp

Правда если у вас нет USBISP, то он и не нужен, можно шить и через Ардуину, но USBISP удобней

Продолжение следует...
 

Вложения

alexlaw

Member
Добавляем поддержку ATtiny2313 в Ардуино IDE
Program an attiny2313 with an Arduino - Arduino Learning
Файл-Настройки-Дополнительные ссылки для менеджера плат - http://drazzy.com/package_drazzy.com_index.json
Инструменты-Плата-Менеджер плат
img5.png
Устанавливаем ATTinyCore
img6.png
Выбираем Clock 8Mhz
Далее - Записать загрузчик
Все.
Если шить Attiny через USBASP, то программатор в соответствии с ресунком выше.
Если через Arduino , то программатор Arduino as ISP.
И последнее распиновка ATTINY2313A-PU
img7.png
 

alexlaw

Member
Поробовал задействовать оба таймера Timer1 и Timer0
Timer1 - в режиме Normal
Timer0 - в режиме СТС -сброс при совпадении
Код:
//http://arduinolearning.com/code/program-attiny2313-arduino.php
//https://blog.3d-logic.com/2015/01/21/arduino-and-the-tm1637-4-digit-seven-segment-display/
#include <avr/interrupt.h>
const int clock1 = 6;
const int data1 = 7;
                 /*0*/ /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ /*6*/ /*7*/ /*8*/ /*9*/
//uint8_t digits2[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f };
uint8_t digits1[] = { 0x3f, 0x30, 0x5b, 0x79, 0x74, 0x6d, 0x6F, 0x38, 0x7f, 0x7D };
uint8_t t;
uint8_t minutes1;
uint8_t seconds1;
byte dot = 128;//двоеточие на дисплее индикатора
byte b = 0;
byte a = 31;
void setup() {
  // put your setup code here, to run once:
pinMode(clock1, OUTPUT);
pinMode(data1, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
start(clock1,data1);
writeValue(clock1,data1,0x8c);
stop(clock1,data1);
// clear display
write(clock1,data1,0x00, 0x00, 0x00, 0x00);
t=0;
    //запускаем таймер                                                                                                                        
    setupInterrupt1();
    setupInterrupt0();
}

void loop() {
if ((t % 2)==0){
  dot=128;
} else {dot=0;}
if (t==3600){t=0;}
minutes1 = (byte)((t / 60) % 60);
seconds1 = (byte)(t % 60);
write(clock1,data1,digits1[seconds1 % 10],digits1[seconds1 / 10] | dot,digits1[minutes1 % 10],digits1 [minutes1 / 10]);
delay(5);

}

void write(int clock,int data,uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
{
start(clock,data);
writeValue(clock,data,0x40);
stop(clock,data);
start(clock,data);
writeValue(clock,data,0xc0);
writeValue(clock,data,first);
writeValue(clock,data,second);
writeValue(clock,data,third);
writeValue(clock,data,fourth);
stop(clock,data);
}

void start(int clock,int data)
{
digitalWrite(clock,HIGH);//send start signal to TM1637
digitalWrite(data,HIGH);
delayMicroseconds(5);
digitalWrite(data,LOW);
digitalWrite(clock,LOW);
delayMicroseconds(5);
}


void stop(int clock,int data)
{
digitalWrite(clock,LOW);
digitalWrite(data,LOW);
delayMicroseconds(5);
digitalWrite(clock,HIGH);
digitalWrite(data,HIGH);
delayMicroseconds(5);
}

bool writeValue(int clock,int data,uint8_t value)
{
for(uint8_t i = 0; i < 8; i++)
{
digitalWrite(clock, LOW);
delayMicroseconds(5);
digitalWrite(data, (value & (1 << i)) >> i);
delayMicroseconds(5);
digitalWrite(clock, HIGH);
delayMicroseconds(5);
}
// wait for ACK
digitalWrite(clock,LOW);
delayMicroseconds(5);
pinMode(data,INPUT);
digitalWrite(clock,HIGH);
delayMicroseconds(5);
bool ack = digitalRead(data) == 0;
pinMode(data,OUTPUT);
return ack;
}
void setupInterrupt1()
{
/*В состав таймера/счетчика входят следующие регистры ввода/вывода:
16битный счетный регистр TCNT1;
16битный регистр захвата ICR1;
два 16битных регистра сравнения — OCR1A и OCR1B;
три 8битных регистра управления — TCCR1A, TCCR1B и TCCR1C.
Каждый из 16битных регистров физически размещается в двух регист
рах ввода/вывода, названия которых получаются добавлением к названию
регистра  буквы  «H»  (старший  байт)  и  «L»  (младший  байт).  Счетный
регистр таймера/счетчика T1 TCNT1, например, размещается в регистрах
TCNT1H:TCNT1L.*/
 
//Разрешение прерывания осуществляется установкой в 1 бита TOIE1
//TIMSK - регистр маски прерываний
  TIMSK &= ~(1 << TOIE1);// Clear bit
//OCIE1B - Флаг разрешения прерывания по совпадению "В" Т1
//OCIE1A - Флаг разрешения прерывания по совпадению "А" Т1
  TIMSK &= ~((1 << OCIE1A) | (1 << OCIE1B));// Clear bit
//Режим Normal
//Это  наиболее  простой  режим  работы  16битного  таймера/счетчика.
//В данном режиме счетный регистр функционирует как обычный суммирующий счетчик.
  TCCR1A &= ~((1 << WGM11) | (1 << WGM10));
  TCCR1B &= ~((1 << WGM13) | (1 << WGM12));
 
  //Fcpu = 8000000 Гц
  //Период тактового сигнала микроконтроллера Tcpu = 1/Fcpu
  //Период тактового сигнала таймера Т1 равен Tt1 = (1/Fcpu)/k = k/Fcpu
  //256/8000000=0.032 мс
  //Делим требуемый интервал времени (1000 мс) на длительность одного такта таймера
  //1000/0.032=31250
  //2^16 + 1 - 31250 = 34287;
  //Выбор источника тактового сигнала таймера/счетчика T1 clk I/O /256

  //clk I/O
  //TCCR1B |= (1 << CS10);// Set bits
  //TCCR1B &= ~((1 << CS11) | (1 << CS12));// Clear bit

  //clk I/O /8
  //TCCR1B |= (1 << CS11);// Set bits
  //TCCR1B &= ~((1 << CS10) | (1 << CS12));// Clear bit

  //clk I/O /64
  //TCCR1B |= (1 << CS11)  | (1 << CS10); // Set bits
  //TCCR1B &= ~(1 << CS12);           // Clear bit

  //clk I/O /256
  TCCR1B |= (1 << CS12);// Set bits
  TCCR1B &= ~((1 << CS10) | (1 << CS11));// Clear bit

  //clk I/O /1024
  //TCCR1B |= (1 << CS12)  | (1 << CS10); // Set bits
  //TCCR1B &= ~(1 << CS11);           // Clear bit

  /* Save value globally for later reload in ISR */
TCNT1=34287;
//Флаг разрешения прерывания по переполнению
TIMSK |= (1 << TOIE1);// Set bits
 
}
void setupInterrupt0()
{
TIMSK &= ~(1 << TOIE0);// Clear bit  - запрещаем прерывания по переполнению
TIMSK &= ~((1 << OCIE0A) | (1 << OCIE0B));// Clear bit   - запрещаем прерывания по совпадению
//TCCR0A &= ~((1 << WGM01) | (1 << WGM00));// Clear bit - режим Normal
////режим СТС
TCCR0B &= ~(1 << WGM02);// Clear bit
TCCR0A &= ~(1 << WGM00);// Clear bit
TCCR0A |= (1 << WGM01);// Set bits
////Период тактового сигнала таймера Т0
//1024/8000000=0.128 мс
//длительность до совпадения при OCR0A = 254
//254*0,128=32,51 мс
//1000/32.51=30.76 31*32.51=1007.81 (31 совпадение для 1 сек)

  //clk I/O /1024
  TCCR0B |= (1 << CS02)  | (1 << CS00); // Set bits
  TCCR0B &= ~(1 << CS01);           // Clear bit
OCR0A = 254;
//режим СТС
TIMSK &= ~(1 << OCIE0B);// Clear bit
TIMSK |= (1 << OCIE0A);// Set bits
//Флаг разрешения прерывания по переполнению
// TIMSK |= (1 << TOIE0);// Set bits
}

//Install the Interrupt Service Routine (ISR) for Timer1 overflow.
ISR(TIMER1_OVF_vect) {
  TCNT1=34287;
// b=!b;
// digitalWrite(12,b);
  t++;
}
//Install the Interrupt Service Routine (ISR) .
ISR(TIMER0_COMPA_vect) {
  a--;
  if (a<=0){
   b=!b;
  digitalWrite(12,b);
  a=31; 
  }
}
Светодиод подключенный к PB3(pin12) - мигает раз в секунду и на индикаторе отображается счет времени.
PS:
Сделал режим СТС, тк ISR(TIMER0_OVF_vect) - ошибка компиляции (пока не разобрался)
img8.png
 

alexlaw

Member
Немного ошибся в скетче
Исправить - uint16_t t;//uint16_t | unsigned int, word | от 0 до 65535
 

alexlaw

Member
Небольшой пример кода, для режима Power Down с WatchDog
Раз в 8 сек Тинька дергает 12-ой ногой, остальное время спит
Код:
void setup() {
pinMode(12, OUTPUT);
watch_dog_ext();
}

void loop() {
  digitalWrite(12,1);
  delay(500);
  digitalWrite(12,0);
  sleepNow();
  delay(500);
}

void sleepNow() {
/*
* Idle  (режим холостого хода)
* В этом режиме прекращается формирование тактовых сигналов clk CPU и  clk FLASH .
* При  этом  ЦПУ  микроконтроллера  останавливается,  а  все остальные  периферийные  устройства 
* (интерфейсные  модули,  таймеры/счетчики,  аналоговый  компаратор,  АЦП,  сторожевой  таймер),
* а также  подсистема  прерываний  продолжают  функционировать.
*/
/*Если компаратор не используется, то при переводе микроконтроллера в
* режим Idle или ADC Noise Reduction его необходимо отключить. В других
* «спящих» режимах модуль аналогового компаратора отключается автома
* тически. */  
DIDR |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов 
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
/*
*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/

//Режим энергосбережения
//MCUCR &= ~((1 << SM1) | (1 << SM0));// Clear bit  - Idle -не у меня не работает?
MCUCR |= (1 << SM0);// Set bits - Power Down
MCUCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
MCUCR &= ~(1 << SE);// Clear bit - sleep_disable
}

void watch_dog_ext(){
//расширенный  сторожевой  таймер
/*
* для выключения таймера (сброса бита WDE) необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать 0 в бит WDE.
*/
/*
* Обратите внимание на то, что состояние флага сброса WDRF регистра MCUSR отменяет состояние бита WDE. Это означает, что бит WDE уста
* новлен всегда, когда установлен флаг WDRF, поэтому перед сбросом WDE необходимо также сбросить WDRF.
*/
//MCUSR &= ~(1 << WDRF);// Clear bit
//WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//WDTCSR &= ~(1 << WDE);// Clear bit
/*
* Для изменения периода таймаута необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать требуемое значение в биты WDP3:0 и WDE, одновременно сбрасывая бит WDCE.
* Перед  изменением  битов  WDP3:0  сторожевой  таймер  рекомендуется сбрасывать.
*/
WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//8 сек
WDTCSR |= (1 << WDP0)  | (1 << WDP3); // Set bits
WDTCSR &= ~((1 << WDP1)  | (1 << WDP2));// Clear bit
WDTCSR &= ~(1 << WDCE);// Clear bit
WDTCSR |= (1 << WDE);// Set bits
}
Сколько кушает тока, не замерял
 

alexlaw

Member
WatchDog в режиме прерывания (в предыдущем примере в режиме сброса)
Код:
byte a = 0;
void setup() {
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
watch_dog_ext();
}
void loop() {
  digitalWrite(12,a);
  digitalWrite(13,0);
  sleepNow();
  digitalWrite(12,a);
  delay(500);
}
void sleepNow() {
/*
* Idle  (режим холостого хода)
* В этом режиме прекращается формирование тактовых сигналов clk CPU и  clk FLASH .
* При  этом  ЦПУ  микроконтроллера  останавливается,  а  все остальные  периферийные  устройства
* (интерфейсные  модули,  таймеры/счетчики,  аналоговый  компаратор,  АЦП,  сторожевой  таймер),
* а также  подсистема  прерываний  продолжают  функционировать.
*/
/*Если компаратор не используется, то при переводе микроконтроллера в
* режим Idle или ADC Noise Reduction его необходимо отключить. В других
* «спящих» режимах модуль аналогового компаратора отключается автома
* тически. */ 
DIDR |= (1 << AIN1D)  | (1 << AIN0D ); // Set bits - отключения  входных  цифровых буферов
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
/*
*Аналогоцифровой преобразователь
* Если функционирование АЦП разрешено, то он будет работать во всех
* «спящих»  режимах.  Соответственно,  для  снижения  потребляемого  тока
* модуль АЦП необходимо отключать перед переводом микроконтроллера в
* любой из энергосберегающих режимов.
*/
//Режим энергосбережения
//MCUCR &= ~((1 << SM1) | (1 << SM0));// Clear bit  - Idle -не у меня не работает?
MCUCR |= (1 << SM0);// Set bits - Power Down
MCUCR |= (1 << SE);// Set bits -  sleep_enable
asm ("sleep");
MCUCR &= ~(1 << SE);// Clear bit - sleep_disable
}
void watch_dog_ext(){
//расширенный  сторожевой  таймер
/*
* для выключения таймера (сброса бита WDE) необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать 0 в бит WDE.
*/
/*
* Обратите внимание на то, что состояние флага сброса WDRF регистра MCUSR отменяет состояние бита WDE. Это означает, что бит WDE уста
* новлен всегда, когда установлен флаг WDRF, поэтому перед сбросом WDE необходимо также сбросить WDRF.
*/
//MCUSR &= ~(1 << WDRF);// Clear bit
//WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//WDTCSR &= ~(1 << WDE);// Clear bit
/*
* Для изменения периода таймаута необходимо выполнить следующие действия:
* 1. Одной командой записать 1 в биты WDE и WDCE.
* 2. В течение следующих четырех тактов записать требуемое значение в биты WDP3:0 и WDE, одновременно сбрасывая бит WDCE.
* Перед  изменением  битов  WDP3:0  сторожевой  таймер  рекомендуется сбрасывать.
* Сброс сторожевого таймера осуществляется командой WDR.
*/
asm ("WDR");
WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
//4 сек
WDTCSR |= (1 << WDP3); // Set bits
WDTCSR &= ~((1 << WDP0)  | (1 << WDP1)  | (1 << WDP2));// Clear bit
WDTCSR &= ~(1 << WDCE);// Clear bit

MCUSR &= ~(1 << WDRF);// Clear bit
WDTCSR |= (1 << WDE)  | (1 << WDCE); // Set bits
WDTCSR &= ~(1 << WDE);// Clear bit

WDTCSR |= (1 << WDIE);// Set bits - Разрешение прерывания от сторожевого таймера (сбрасывается после сраб тайм аута)
}
ISR(WDT_OVERFLOW_vect) { //4 сек
digitalWrite(13,1); 
a=!a;
}
 

alexlaw

Member
Здравствуйте.
Кто нибудь писал на Ассемблере для Attiny2313?
Хочу переписать на Ассемблере управление TM1637 в виде ассемблеровских вставок.
От Arduino IDE отказываться не хочу.
Помигать диодами я смог.
Код:
void setup() {
asm volatile
  (
    /*
     *DDRB - регистр направления данных порта B
     *$17 r23
     *PB3 - pin12,PB4 - pin13
     */
    
    "ldi r23,0b00011000" "\n"
    "out 23,r23" "\n" //pinMode(12, OUTPUT);pinMode(13, OUTPUT);
  );

}

void loop() {
   asm volatile
  (
    /*
     *PORTB - регистр данных порта B
     *$18 r24
     */  
//digitalWrite(12,1);digitalWrite(13,1);
    
"ldi r24,0b00011000" "\n"
"out 24,r24" "\n"
  );
delay(500);
   asm volatile
  (
//digitalWrite(12,0);digitalWrite(13,0);
  
"ldi r24,0b00000000" "\n"
"out 24,r24" "\n"
);
delay(500);
}
 

alexlaw

Member
Вот мигание полностью на ассемблере
Код:
void setup() {
asm volatile
  (
    /*
     *DDRB - регистр направления данных порта B
     *$17 r23
     *PB3 - pin12,PB4 - pin13
     */    
    "ldi r23,0b00011000" "\n"
    "out 23,r23" "\n"
  );
}

void loop() {
   asm volatile
  (
    /*
     *PORTB - регистр данных порта B
     *$18 r24
     */     
"ldi r24,0b00011000" "\n"
"out 24,r24" "\n"    
//; Generated by delay loop calculator
//; at http://www.bretmulvey.com/avrdelay.html
//; Delay 4 000 000 cycles
//; 500ms at 8.0 MHz
    "ldi  r18, 21""\n"
    "ldi  r19, 75""\n"
    "ldi  r20, 191""\n"
"L1: dec  r20""\n"
    "brne L1""\n"
    "dec  r19""\n"
    "brne L1""\n"
    "dec  r18""\n"
    "brne L1""\n"
    "nop""\n"
"ldi r24,0b00000000" "\n"
"out 24,r24" "\n"
    "ldi  r18, 21""\n"
    "ldi  r19, 75""\n"
    "ldi  r20, 191""\n"
"L2: dec  r20""\n"
    "brne L2""\n"
    "dec  r19""\n"
    "brne L2""\n"
    "dec  r18""\n"
    "brne L2""\n"
    "nop""\n"
  ); 
}
 

alexlaw

Member
Еще вариант с дисплеем на max7219.
Код:
int slaveSelect=14;
int din=6;
int clk=15;
byte btNum[10]={126,48,109,121,51,91,95,112,127,123};
void setup() {
  pinMode(slaveSelect, OUTPUT);
  pinMode(din, OUTPUT);
  pinMode(clk, OUTPUT);
sendCommand(12,1); //normal mode (default is shutdown mode)
sendCommand (15,0); //Display test off
sendCommand (10,6); //set medium intensity (range is 0-15)
sendCommand (11, 7); //7219 digit scan limit command
sendCommand (9, 0); //decode command, use standard 7-segment digits
sendCommand (8, 79);
sendCommand (7, 91);
sendCommand (6, 103);
sendCommand (5, 1);
sendCommand (4, 127);
sendCommand (3, 109);
sendCommand (2, 95);
sendCommand (1, 95);
}

void loop() {
delay(5);

}
void sendCommand(byte cmd, byte data)
{
digitalWrite(slaveSelect, LOW); //chip select is active low
// передать старший байт
shiftOut(din, clk, MSBFIRST, cmd);
// передать младший байт
shiftOut(din, clk, MSBFIRST, data);
digitalWrite(slaveSelect,HIGH);
}
IMG_20190531_233111.jpg
 

alexlaw

Member
Датчик температуры ds18b20.
Код:
//за основу взята библиотека http://mypractic.ru/downloads/arduino/OneWire.zip
//DQ датчика к + через резистор 4.7к
#include "OneWire1.h"
OneWire sensDs (7);
byte bufData[2];  // буфер данных
int slaveSelect=14;
int din=6;
int clk=15;
//датчик к PIN7 - PD5 - PORTD
byte Num[10] ={126,48,109,121,51,91,95,112,127,123};
unsigned char temp;
void setup() {
  pinMode(slaveSelect, OUTPUT);
  pinMode(din, OUTPUT);
  pinMode(clk, OUTPUT);
sendCommand(12,1); //normal mode (default is shutdown mode)
sendCommand (15,0); //Display test off
sendCommand (10,6); //set medium intensity (range is 0-15)
sendCommand (11, 7); //7219 digit scan limit command
sendCommand (9, 0); //decode command, use standard 7-segment digits
sendCommand (8, 0);
sendCommand (7, 0);
sendCommand (6, 0);
sendCommand (5, 0);
sendCommand (4, 1);
sendCommand (3, 1);
sendCommand (2, 99);
sendCommand (1, 78);//t*C  --*
}

void loop() {
sensDs.reset();  // сброс шины
sensDs.write(0xCC, 0); // пропуск ROM
sensDs.write(0x44, 0); // инициализация измерения
delay(900);  // пауза 0,9 сек
sensDs.reset();  // сброс шины
sensDs.write(0xCC, 0); // пропуск ROM
sensDs.write(0xBE, 0); // команда чтения памяти датчика
sensDs.read_bytes(bufData, 2);  // чтение памяти датчика, 2 байта
temp = bufData[0]>>4 | bufData[1]<<4;
sendCommand (4, Num[temp/10]);
sendCommand (3, Num[temp % 10]);
delay(5000);
}
void sendCommand(byte cmd, byte data)
{
digitalWrite(slaveSelect, LOW); //chip select is active low
// передать старший байт
shiftOut(din, clk, MSBFIRST, cmd);
// передать младший байт
shiftOut(din, clk, MSBFIRST, data);
digitalWrite(slaveSelect,HIGH);
}
библиотека
OneWire1.zip
IMG_20190609_011740.png
 

Вложения

alexlaw

Member
Аналоговый компаратор.
comparator.png
Код:
void setup() {
pinMode(12, OUTPUT);
ACSR &= ~(1 << ACIE);// Clear bit - Запрещение прерывания от компаратора
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
// Set bits - отключения  входных  цифровых буферов
DIDR |= (1 << AIN1D)  | (1 << AIN0D );
pinMode(9, INPUT);// AIN0
pinMode(10, INPUT);// AIN1
//изменение состояния выхода компаратора с 0 на 1
ACSR |= (1 << ACIS1)  |  (1 << ACIS0); // Set bits
ACSR &= ~(1 << ACD);// Clear bit - Включение компаратора
}

void loop() {
if (ACSR & (1 << ACO)) //если бит ACO установлен
{
   digitalWrite(12,1);
} else {
  digitalWrite(12,0);
}
delay(1000);
}
Код:
void setup() {
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
ACSR &= ~(1 << ACIE);// Clear bit - Запрещение прерывания от компаратора
ACSR |= (1 << ACD);// Set bits - Выключение компаратора
// Set bits - отключения  входных  цифровых буферов
DIDR |= (1 << AIN1D)  | (1 << AIN0D );
pinMode(9, INPUT);// AIN0
pinMode(10, INPUT);// AIN1
//изменение состояния выхода компаратора с 0 на 1
ACSR |= (1 << ACIS1)  |  (1 << ACIS0); // Set bits
ACSR &= ~(1 << ACD);// Clear bit - Включение компаратора
ACSR |= (1 << ACIE);// Set bits - Разрешение прерывания
}
void loop() {
if (ACSR & (1 << ACO)) //если бит ACO установлен
{
   digitalWrite(12,1);
} else {
  digitalWrite(12,0); 
}
delay(1000);
digitalWrite(13,0);
ACSR |= (1 << ACIE);// Set bits - Разрешение прерывания
}
ISR(ANA_COMP_vect){
    digitalWrite(13,1);
    ACSR &= ~(1 << ACIE);// Clear bit - Запрещение прерывания
}
 

alexlaw

Member
Универсальный синхронный/асинхронный приемо\передатчик - USART
USART.png
Код:
byte b=0;
void setup() {
pinMode(12, OUTPUT);
digitalWrite(12,0);
initUSART();
}

void loop() {
  delay(1000);
}

void initUSART() {
//запретить прнерывания от передатчика
UCSRB &= ~((1 << RXCIE) | (1 << TXCIE) | (1 << UDRIE)); // Clear bit
//Если бит UMSEL сброшен в 0, то модуль работает в асинхронном режиме
//USBS Количество стопбитов. Если бит сброшен в 0, то передатчик посылает 1 стопбит,
//если установлен в 1, то 2 стопбита.
//UCPOL  При работе в асинхронном режиме он должен быть сброшен в 0. USART Mode: Asynchronous
//UPM1 UPM0 - Управление схемой контроля четности - 0 0 Выключена
UCSRC &= ~((1 << UMSEL) | (1 << USBS) | (1 << UCPOL) | (1 << UPM1) | (1 << UPM0)); // Clear bit
//Определение размера слова данных - 8 бит
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); // Set bits
UCSRA &= ~(1 << UCSZ2); // Clear bit
UCSRC &= ~(1 << U2X); // Clear bit  обычная скорость
// Speed = 9600
UBRRH = 0;
UBRRL = 51;
//Разрешение приема
UCSRB |=(1<<RXEN); // Set bits
UCSRB |= (1<<RXCIE); // Set bits Разрешение прерывания по завершении приема.

}
//прерывания по завершении приема.
//9dddddddddddddddddddd9 - сработает 22 раза
ISR(USART_RX_vect){
  if (UDR==0x39)//цифра 9 - сработает 2 раза
  {
    b=!b;
    digitalWrite(12,b);   
  }  
}
Подключаем ардуино к компу.
Для передачи на Тиньку используем Инструменты-Монитор порта-<<отправить>>
скорость 9600.
 

alexlaw

Member
Код:
char charVar[] ={0x41,0x42,0x43,0x44,'E','F','\n','\r'};
byte b=0;
void setup() {
pinMode(12, OUTPUT);
digitalWrite(12,0);
initUSART();
}
void loop() {
for (int i=0;i < 8;i++) {
  USART_Transmit(charVar[i]);
}
delay(2000);
}

void initUSART() {
//UCSRB &= ~((1 << TXEN) | (1 << RXEN)); // Clear bit 
//запретить прнерывания от передатчика
UCSRB &= ~((1 << RXCIE) | (1 << TXCIE) | (1 << UDRIE)); // Clear bit
//Если бит UMSEL сброшен в 0, то модуль работает в асинхронном режиме
//USBS Количество стопбитов. Если бит сброшен в 0, то передатчик посылает 1 стопбит,
//если установлен в 1, то 2 стопбита.
//UCPOL  При работе в асинхронном режиме он должен быть сброшен в 0. USART Mode: Asynchronous
//UPM1 UPM0 - Управление схемой контроля четности - 0 0 Выключена
UCSRC &= ~((1 << UMSEL) | (1 << USBS) | (1 << UCPOL) | (1 << UPM1) | (1 << UPM0)); // Clear bit
//Определение размера слова данных - 8 бит
UCSRC |= (1<<UCSZ1) | (1<<UCSZ0); // Set bits
UCSRA &= ~(1 << UCSZ2); // Clear bit
//UCSRC &= ~(1 << U2X); // Clear bit  обычная скорость
// Speed = 9600
UBRRH = 0;
UBRRL = 51;
//Разрешение передачи
UCSRB |=(1<<TXEN); // Set bits
//UCSRB |= (1<<TXCIE); // Set bits Разрешение прерывания по завершении передачи.
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */ 
   while ( !( UCSRA & (1<<UDRE))) {   
   };
   UDR = data; 
   b=!b;
   digitalWrite(12,b);    
}
//ISR(USART_TX_vect){
 
//  }
USART1.png
 

alexlaw

Member
Код:
char charVar[64];
byte b=0;
byte a=0;
boolean c = false;
void setup() {
pinMode(12, OUTPUT);
digitalWrite(12,0);
//---------------------
//CodeVisionAVR V2.05.0
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x33;
//---------------------
UCSRB |= (1<<RXCIE) | (1<<TXCIE); // Set bits Разрешение прерывания по завершении приема и передачи.
}

void loop() {
if (c){
USART_Transmit('*');
for (int i=0;i < a;i++) {
  USART_Transmit(charVar[i]);
  charVar[i]=0;
}
USART_Transmit('*');
USART_Transmit('\n');
USART_Transmit('\r');  
}
a=0;
delay(2000);
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */
   while ( !( UCSRA & (1<<UDRE))) {  
   };
   UDR = data;
   b=!b;
   digitalWrite(12,b);   
}
ISR(USART_RX_vect){
  charVar[a]=UDR;
  c=true;
  a++;
  if(a>64)a=0;
}
ISR(USART_TX_vect){
c=false;
}
Прием и передача обратно.
Принимаются данные и отправляются обратно, в начале и в конце ставится звездочка.
PS В ардуину залит "Blink", если в ардуине есть Serial.begin(9600);
то в Мониторе порта принятые от Тиньки данные не отображаются.
Пока не разобрался
 

alexlaw

Member
Прошу прощения за ошибку в коде
if(a>64)a=0;
Код:
char charVar[64];
byte b=0;
byte a=0;
boolean c = false;
void setup() {
pinMode(12, OUTPUT);
digitalWrite(12,0);
//---------------------
//CodeVisionAVR V2.05.0
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x33;
//---------------------
UCSRB |= (1<<RXCIE) | (1<<TXCIE); // Set bits Разрешение прерывания по завершении приема и передачи.
}

void loop() {
if (c){
USART_Transmit('*');
//если принято байт больше, чем размер бефера  charVar, то
//данные записанные первыми - перезаписываются, остальные данные есть в буфере,
//но назад не отпр
if (a==0)a=64;
for (int i=0;i < a;i++) {
  USART_Transmit(charVar[i]);
  charVar[i]=0;
}
USART_Transmit('*'); 
USART_Transmit('\n');
USART_Transmit('\r');   
}
a=0;
delay(2000);
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */ 
   while ( !( UCSRA & (1<<UDRE))) {   
   };
   UDR = data; 
   b=!b;
   digitalWrite(12,b);    
}
ISR(USART_RX_vect){
  charVar[a]=UDR;
  c=true;
  a++;
  if(a>63)a=0;
}
ISR(USART_TX_vect){
c=false;
}
USART2.png
 

alexlaw

Member
USART в режиме 1-WIRE.
OneWire.png
Код:
//http://microsin.net/programming/AVR/avr318-dallas-1-wire-master.html
//https://www.maximintegrated.com/en/app-notes/index.mvp/id/214
byte bufData[9];  // буфер данных
byte a=0;
void setup() {
pinMode(12, OUTPUT);
digitalWrite(12,0); 
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
//Разрешение прерывания по завершении приема и передачи.
UCSRA=0x00;
UCSRB=0xD8;
UCSRC=0x06;
UBRRH=0x00;
UBRRL=0x33;
}

void loop() {
USART_Transmit(0xF0);
delay(2000);
}
void USART_Transmit(unsigned int data)
{
   /* Ждать очистки буфера передатчика */ 
   while ( !( UCSRA & (1<<UDRE))) {   
   };
   UDR = data;     
}
ISR(USART_RX_vect){
  bufData[a]=UDR;
//скорость передачи 9600 бод. Передача 0xF0 от UART формирует правильный импульс сброса.
//Если устройства нет, полученное значение будет равно передаваемому значению.
//Одно подчиненное устройство, работающее с минимальной внутренней синхронизацией, изменит ответ на 0xE0.
//Один ведомый, работающий с максимальной внутренней синхронизацией, изменит ответ на 0x90. 
  if (UDR==0xE0)
  {digitalWrite(12,1);} else {
   digitalWrite(12,0);
  }
  a++;
  if(a>8)a=0;

}
//ISR(USART_TX_vect){
//
//}
У меня DS18b20 ответил - 0xF0.
Можно двигаться дальше ...
IMG_20190622_164703.jpg
 

nikolz

Well-known member
alexlaw,
Полагаю, что схему можно существенно упростить
два транзистора заменить одним диодом.
Подумайте над этим.
 
Сверху Снизу