ATtiny85 1001 применение.

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

Ну а сеанс связи как проходит? Вызвал - ответил, оценка слышимости, qth, name, 73, как обычно?

Morroc
Offline
Зарегистрирован: 24.10.2016

Green пишет:

В 2002-м воскрес, как я понял? И что работает кто то с ним? Как это выглядит?

Это 3й WDT сработал, наверное )

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

Morroc пишет:

Green пишет:

В 2002-м воскрес, как я понял? И что работает кто то с ним? Как это выглядит?

Это 3й WDT сработал, наверное )

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

Morroc
Offline
Зарегистрирован: 24.10.2016

Сильно заморочено это все, я в спутники залез только когда QO-100 запустили - халява )

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

ua6em пишет:

обычный сеанс связи, только крутить частоту на доплер надо, лучше когда это делает компьютер )))


Ужос! Резиновая женщина. Никакой романтики.(

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

Morroc пишет:

Это 3й WDT сработал, наверное )

И WDT настроен был на срабатывание в 21 год.) А если серьёзно, просто повезло.
PS. А что нельзя разве было разработчиками предусмотреть отключение разряженного/КЗ аккумулятора...

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

Green пишет:

Morroc пишет:

Это 3й WDT сработал, наверное )

И WDT настроен был на срабатывание в 21 год.) А если серьёзно, просто повезло.
PS. А что нельзя разве было разработчиками предусмотреть отключение разряженного/КЗ аккумулятора...

в 1974 году компоненты были весьма ограничены, даже у них, ты жеж не забывай строилось по хоббийной тематике, вот уже на фазу-3д скидывались, проект создания обошёлся в 5 миллионов долларов, да и весил уже тонны...
а  WDT перезапустил (и перезапускает с периодичностью) когда появляется питание

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

Morroc пишет:

Сильно заморочено это все, я в спутники залез только когда QO-100 запустили - халява )

Не Карена девайс случаем делал?

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

BLINK на первом таймере с использованием прерывания.
 



bool leds;
uint16_t divs = 3; // программный делитель
volatile uint16_t clocks;

ISR (TIMER1_COMPA_vect) {
  clocks++;
  if (clocks >= divs) {
    leds = !leds;
    clocks = 0;
    digitalWrite(PB1,leds);
  }
}

void setup() {
  DDRB = (1 << PB1);
  OCR1A = 83;
  OCR1C = 165;
  TCCR1 = (1 << PWM1A) | (15 << CS10); // |(1<<COM1A0)2)|(1<<CS11);
  TIMSK = 1 << OCIE1A;
}

void loop() {
 // digitalWrite(PB1,leds);
}

 

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

Моё ИМХО.
Вот этих магических цифр быть не должно.
leds желательно volatile.
По красивому leds = (bool)!leds;
DDR, OCR и пр. быть не должно.
Должна быть логика а не физика!
Это же Си!)

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

Green пишет:

Моё ИМХО.

научи!

и таки да волатильный leds откушает еще 20 байт памяти программ, пусть сидит в регистре где ему и место, я вообще на асме делал один регистр с побитным сохранением флагов, 8 переменных однако влезает )))

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

Ну как тут научишь! Очень много писанины.
Цели разные, критерии разные...)
За байтами гоняться не стоит. Только в исключительных случаях!)

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

Лично я делаю так.
blink.h

// include "main.h"


#define LED               1             //pin

#define DIVS              3             //программный делитель
#define PWM_VALUE1        83
#define PWM_VALUE2        (166 - 1)

#define out(x)            (DDRB = 1<<(x))
#define toggle(x)         (PINB = 1<<(x))

#define timer_init()      do { OCR1A = PWM_VALUE1; OCR1C = PWM_VALUE2; \
                          TCCR1 = 1<<PWM1A | 5<<CS10; TIMSK = 1<<OCIE1A; } while (0)

#define ISR_VECTOR        TIMER1_COMPA_vect
#define INTERRUPT(x)      ISR(x)

blink.cpp

// blink на первом таймере с использованием прерывания.
#include "blink.h"


void setup() {
  led_init();                           //настроим пин
  timer_init();                         // таймер
}


INTERRUPT(ISR_VECTOR) {
  static uint8_t clocks;
  if (++clocks >= DIVS) {
    clocks = 0;
    toggle(LED);
  }
}


void loop() {
}

Только зачем тут pwm, можно же CTC?
Oops!

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

Green пишет:

Только зачем тут pwm, можно же CTC?
Oops!

есть и СТС есть и PWM, изучаю регистры

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

"Тихо сам с собою я веду беседы")
Oops - это я там глупость написал. Исправился.)

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

Green пишет:

"Тихо сам с собою я веду беседы")
Oops - это я там глупость написал. Исправился.)

У меня твой скетч в такой конфигурации заработал:
 

// include "main.h"


#define LED               1             //pin
#define DIVS              3             //программный делитель
#define PWM_VALUE1        83
#define PWM_VALUE2        (166 - 1)
#define out(x)            (DDRB = 1<<(x))
#define toggle(x)         (PINB = 1<<(x))
#define timer_init()      do { OCR1A = PWM_VALUE1; OCR1C = PWM_VALUE2; \
                          TCCR1 = 1<<PWM1A | 15<<CS10; TIMSK = 1<<OCIE1A; } while (0)
#define ISR_VECTOR        TIMER1_COMPA_vect
#define INTERRUPT(x)      ISR(x)

void setup() {
  out(LED);
//  led_init();                           //настроим пин
  timer_init();                         // таймер
}


INTERRUPT(ISR_VECTOR) {
  static uint8_t clocks;
  if (++clocks >= DIVS) {
    clocks = 0;
    toggle(LED);
  }
}


void loop() {
}

 

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

Декодер CW: (взято отсюда)
 

/*  2015 / 2016 / 2017
 *  Morse decoder for Attiny85 and the #AttinyArcade by Andy Jackson (M0RCL) - Twitter @andyhighnumber
 *   
 *  Displays morse code coming in on the assigned pin in real time, via a 5-line scrolling display 
 *   
 *  Inspired by, and designed to run on the Attiny Arcade hardware. Check out www.webboggles.com for info on this hardware.
 *   
 *  When running, use:
 *   - The right button to send morse
 *   - The left button to start and stop the software running
 *   
 *  Any code not covered by the licences below can be used freely with attribution. No warranties whatsoever are provided or implied.
 *   
 *  ****************************************************************************************************
 *  * The core morse decoder here is a slightly modified version of WB7FHC's Morse Code Decoder v. 1.1 *
 *  * (c) 2014, Budd Churchward - WB7FHC                                                               *
 *  * This is an Open Source Project                                                                   *
 *  * http://opensource.org/licenses/MIT                                                               *
 *  * Search YouTube for 'WB7FHC' to see several videos of this project as it was developed.           *
 *  * Also see https://github.com/kareiva/wb7fhc-cw-decoder                                            *
 *  ****************************************************************************************************
 *  
 *  This sketch is using the screen control and font functions written by Neven Boyanov for the http://tinusaur.wordpress.com/ project
 *  Source code and font files available at: https://bitbucket.org/tinusaur/ssd1306xled
 * 
 *  Sleep code is based on this blog post by Matthew Little:
 *  http://www.re-innovation.co.uk/web12/index.php/en/blog-75/306-sleep-mode...
 */
 
#include <EEPROM.h>
#include "font6x8AJ.h"
#include <avr/pgmspace.h>
#include <avr/sleep.h>
#include <avr/interrupt.h> // needed for the additional interrupt

#define DIGITAL_WRITE_HIGH(PORT) PORTB |= (1 << PORT)
#define DIGITAL_WRITE_LOW(PORT) PORTB &= ~(1 << PORT)

// Routines to set and clear bits (used in the sleep code)
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

// Defines for OLED output
#define SSD1306XLED_H
#define SSD1306_SCL   PORTB4  // SCL, Pin 4 on SSD1306 Board - for webbogles board
#define SSD1306_SDA   PORTB3  // SDA, Pin 3 on SSD1306 Board - for webbogles board
#define SSD1306_SA    0x78  // Slave address

#define FIRSTLINE 2     // The first displayed line of decoded morse on the LCD
#define LASTLINE 6      // The last displayed line of decoded morse on the LCD
#define LINELENGTH 20   // The number of characters on one completed line
#define MAXWORD 17      // The longest any single word can be (needed to manage buffer limits)

// Drawing functions - adapted from those at https://bitbucket.org/tinusaur/ssd1306xled
void ssd1306_init(void);
void ssd1306_xfer_start(void);
void ssd1306_xfer_stop(void);
void ssd1306_send_byte(uint8_t byte);
void ssd1306_send_command(uint8_t command);
void ssd1306_send_data_start(void);
void ssd1306_send_data_stop(void);
void ssd1306_setpos(uint8_t x, uint8_t y);
void ssd1306_fillscreen(uint8_t fill_Data);
void ssd1306_char_f6x8(uint8_t x, uint8_t y, char ch[]);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t bitmap[]);

// Custom draw functions - allow for extra functionality like inverse display
void sendBlock(byte, bool);
void sendByte(byte, bool);

int stopRunning = 0;

// Other generic functions (both originated in code from webboggles.com and the sleep code is by Matthew Little - see above)
void beep(int,int);
void system_sleep(void);
void doNumber (int,int,int);

// Specific main function to decode morse
void decodeMorse(void);

// Variable declarations for decoder
int inputPin = 2;         // input data comes in here (key or decoder)
int audio = 1;            // will store the value we read on this pin
boolean mute = 0;         // Mute the speaker
int letterCount = 0;
int LCDline = FIRSTLINE;          // keeps track of which line we're printing on
boolean ditOrDah = true;  // We have either a full dit or a full dah
int dit;            

// The following values will auto adjust to the sender's speed
int averageDah;                   // A dah should be 3 times as long as a dit
int averageWordGap;               // will auto adjust

boolean characterDone = true; // A full character has been sent

int downTime = 0;        // How long the tone was on in milliseconds
int upTime = 0;          // How long the tone was off in milliseconds
int myBounce = 2;        // Used as a short delay between key up and down
long startDownTime = 0;  // Arduino's internal timer when tone first comes on
long startUpTime = 0;    // Arduino's internal timer when tone first goes off

int currentWordLength = 0;
int currentWordPos = 0;
char currentWord[MAXWORD];
char screenText[LASTLINE-FIRSTLINE+1][LINELENGTH+1];
int lastWordLength = 0;

boolean justDid = true; // Makes sure we only print one space during long gaps

int myNum = 0;           // We will turn dits and dahs into a binary number stored here
char mySet[] ="##TEMNAIOGKDWRUS##QZYCXBJP#L#FVH09#8###7#####/-61#######2###3#45";
char decodedCharacter = ' ';       // We will store the actual character decoded here

// Interrupt handlers
ISR(PCINT0_vect){ // PB0 pin button interrupt           
  stopRunning = 1; // stop the programme :)
}

void playerIncMorse(){ // PB2 pin button interrupt
}


// Arduino stuff - setup
void setup() {
  DDRB = 0b00000010;    // set PB1 as output (for the speaker)
  PCMSK = 0b00000001; // pin change mask: listen to portb bit 1
  GIMSK |= 0b00100000;  // enable PCINT interrupt 
  sei();          // enable all interrupts
}

// Arduino stuff - loop
void loop() { 
//  pinMode(2, INPUT_PULLUP);
//  pinMode(1, OUTPUT);
  
  ssd1306_init();
  ssd1306_fillscreen(0x00);

  ssd1306_char_f6x8(0, 0, "  M O R S E");
  ssd1306_char_f6x8(0, 1, "      D E C O D E R");
  ssd1306_char_f6x8(27, 5, "andy jackson"); // see comments above !

  ssd1306_setpos(16,2); 
  for (int incr = 16; incr < 112; incr++) {
    ssd1306_send_data_start();
    ssd1306_send_byte(B00001010);
    ssd1306_send_data_stop();                    
  }
  ssd1306_setpos(27,4); 
  for (int incr = 0; incr < 72; incr++) {
    ssd1306_send_data_start();
    ssd1306_send_byte(B00100000);
    ssd1306_send_data_stop();                    
  }
  ssd1306_setpos(27,6); 
  for (int incr = 0; incr < 72; incr++) {
    ssd1306_send_data_start();
    ssd1306_send_byte(B00000100);
    ssd1306_send_data_stop();                    
  }

  delay(1500);

  long startT = millis();
  long nowT =0;
  boolean sChange = 0;

  while(digitalRead(0) == HIGH) {
    nowT = millis();
    if (nowT - startT > 2000) {
      sChange = 1;     
      if (mute == 0) { mute = 1; ssd1306_char_f6x8(32, 7, "-- MUTE --"); } else { mute = 0; ssd1306_char_f6x8(31, 7, "- SOUND ON -");  }    
      break;
    }
    if (sChange == 1) break;
  }  
  while(digitalRead(0) == HIGH);

  if (sChange == 0) {
    delay(1500);
    
    ssd1306_init();
    ssd1306_fillscreen(0x00);
  
    stopRunning = 0;
  
    decodeMorse(); 
  
    ssd1306_fillscreen(0x00);
    ssd1306_char_f6x8(11, 1, "----------------");
    ssd1306_char_f6x8(11, 2, " S T O P P E D");
    ssd1306_char_f6x8(11, 3, "----------------");
    ssd1306_char_f6x8(0, 6, "          bye..."); 

    delay(1200);    
  }
  system_sleep();
}

void doNumber (int x, int y, int value) {
    char temp[10] = {0,0,0,0,0,0,0,0,0,0};
    itoa(value,temp,10);
    ssd1306_char_f6x8(x, y, temp);
}

void ssd1306_init(void){
  DDRB |= (1 << SSD1306_SDA); // Set port as output
  DDRB |= (1 << SSD1306_SCL); // Set port as output

  ssd1306_send_command(0xAE); // display off
  ssd1306_send_command(0x00); // Set Memory Addressing Mode
  ssd1306_send_command(0x10); // 00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
  ssd1306_send_command(0x40); // Set Page Start Address for Page Addressing Mode,0-7
  ssd1306_send_command(0x81); // Set COM Output Scan Direction
  ssd1306_send_command(0xCF); // ---set low rowumn address
  ssd1306_send_command(0xA1); // ---set high rowumn address
  ssd1306_send_command(0xC8); // --set start line address
  ssd1306_send_command(0xA6); // --set contrast control register
  ssd1306_send_command(0xA8);
  ssd1306_send_command(0x3F); // --set segment re-map 0 to 127
  ssd1306_send_command(0xD3); // --set normal display
  ssd1306_send_command(0x00); // --set multiplex ratio(1 to 64)
  ssd1306_send_command(0xD5); // 
  ssd1306_send_command(0x80); // 0xa4,Output follows RAM content;0xa5,Output ignores RAM content
  ssd1306_send_command(0xD9); // -set display offset
  ssd1306_send_command(0xF1); // -not offset
  ssd1306_send_command(0xDA); // --set display clock divide ratio/oscillator frequency
  ssd1306_send_command(0x12); // --set divide ratio
  ssd1306_send_command(0xDB); // --set pre-charge period
  ssd1306_send_command(0x40); // 
  ssd1306_send_command(0x20); // --set com pins hardware configuration
  ssd1306_send_command(0x02);
  ssd1306_send_command(0x8D); // --set vcomh
  ssd1306_send_command(0x14); // 0x20,0.77xVcc
  ssd1306_send_command(0xA4); // --set DC-DC enable
  ssd1306_send_command(0xA6); // 
  ssd1306_send_command(0xAF); // --turn on oled panel 
}

void ssd1306_xfer_start(void){
  DIGITAL_WRITE_HIGH(SSD1306_SCL);  // Set to HIGH
  DIGITAL_WRITE_HIGH(SSD1306_SDA);  // Set to HIGH
  DIGITAL_WRITE_LOW(SSD1306_SDA);   // Set to LOW
  DIGITAL_WRITE_LOW(SSD1306_SCL);   // Set to LOW
}

void ssd1306_xfer_stop(void){
  DIGITAL_WRITE_LOW(SSD1306_SCL);   // Set to LOW
  DIGITAL_WRITE_LOW(SSD1306_SDA);   // Set to LOW
  DIGITAL_WRITE_HIGH(SSD1306_SCL);  // Set to HIGH
  DIGITAL_WRITE_HIGH(SSD1306_SDA);  // Set to HIGH
}

void ssd1306_send_byte(uint8_t byte){
  uint8_t i;
  for(i=0; i<8; i++)
  {
    if((byte << i) & 0x80)
      DIGITAL_WRITE_HIGH(SSD1306_SDA);
    else
      DIGITAL_WRITE_LOW(SSD1306_SDA);
    
    DIGITAL_WRITE_HIGH(SSD1306_SCL);
    DIGITAL_WRITE_LOW(SSD1306_SCL);
  }
  DIGITAL_WRITE_HIGH(SSD1306_SDA);
  DIGITAL_WRITE_HIGH(SSD1306_SCL);
  DIGITAL_WRITE_LOW(SSD1306_SCL);
}

void ssd1306_send_command(uint8_t command){
  ssd1306_xfer_start();
  ssd1306_send_byte(SSD1306_SA);  // Slave address, SA0=0
  ssd1306_send_byte(0x00);  // write command
  ssd1306_send_byte(command);
  ssd1306_xfer_stop();
}

void ssd1306_send_data_start(void){
  ssd1306_xfer_start();
  ssd1306_send_byte(SSD1306_SA);
  ssd1306_send_byte(0x40);  //write data
}

void ssd1306_send_data_stop(void){
  ssd1306_xfer_stop();
}

void ssd1306_setpos(uint8_t x, uint8_t y)
{
  if (y>7) return;
  ssd1306_xfer_start();
  ssd1306_send_byte(SSD1306_SA);  //Slave address,SA0=0
  ssd1306_send_byte(0x00);  //write command

  ssd1306_send_byte(0xb0+y);
  ssd1306_send_byte(((x&0xf0)>>4)|0x10); // |0x10
  ssd1306_send_byte((x&0x0f)|0x01); // |0x01

  ssd1306_xfer_stop();
}

void ssd1306_fillscreen(uint8_t fill_Data){
  uint8_t m,n;
  for(m=0;m<8;m++)
  {
    ssd1306_send_command(0xb0+m); //page0-page1
    ssd1306_send_command(0x00);   //low rowumn start address
    ssd1306_send_command(0x10);   //high rowumn start address
    ssd1306_send_data_start();
    for(n=0;n<128;n++)
    {
      ssd1306_send_byte(fill_Data);
    }
    ssd1306_send_data_stop();
  }
}

void ssd1306_char_f6x8(uint8_t x, uint8_t y, char ch[]){
  uint8_t c,i,j=0;
  while(ch[j] != '\0')
  {
    c = ch[j] - 32;
    if(x>126)
    {
      x=0;
      y++;
    }
    ssd1306_setpos(x,y);
    ssd1306_send_data_start();
    for(i=0;i<6;i++)
    {
      ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
    }
    ssd1306_send_data_stop();
    x += 6;
    j++;
  }
}

void system_sleep(void) {
  ssd1306_fillscreen(0x00);
  ssd1306_send_command(0xAE);
  cbi(ADCSRA,ADEN);                    // switch analog to digital converter off
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
  sleep_enable();
  sleep_mode();                        // system actually sleeps here
  sleep_disable();                     // system continues execution here when watchdog timed out 
  sbi(ADCSRA,ADEN);                    // switch analog to digital converter on
  ssd1306_send_command(0xAF);
}

void beep(int bCount,int bDelay){
  if (mute) return;
  for (int i = 0; i<=bCount; i++){digitalWrite(1,HIGH);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}digitalWrite(1,LOW);for(int i2=0; i2<bDelay; i2++){__asm__("nop\n\t");}}
}


/* ------------------------
 *  Main code
 */
void decodeMorse(){
  int wpm = 0;

  averageDah = 240;             // Starting point for auto-adjusting speed
  averageWordGap = averageDah;  // Will auto adjust
  dit = averageDah / 3;         
  lastWordLength = 0;
  letterCount = 0;
  LCDline = FIRSTLINE; 
  currentWordLength = 0;
  currentWordPos = 0;

  for (int i = 700; i>200; i = i - 50){
   beep(30,i);
  }

  ssd1306_char_f6x8(0, 0, "Listening.. WPM:");
  wpm = floor(1200 / (float(averageDah/3.0)) );
  doNumber(96,0,wpm);

  while(stopRunning == 0) {
     audio = digitalRead(inputPin); // What is the tone decoder doing?
  
     if (audio) { 
        keyIsDown();
        while(audio) {
          beep(50,250);
          audio = digitalRead(inputPin);
        }
        }      
     if (!audio) { 
        keyIsUp(); 
      }        
  }
} 


void keyIsDown() {
   // The decoder is detecting our tone
   // The LEDs on the decoder and Arduino will blink on in unison
   
   
   if (startUpTime>0){
     // We only need to do once, when the key first goes down
     startUpTime=0;    // clear the 'Key Up' timer
     }
   // If we haven't already started our timer, do it now
   if (startDownTime == 0){
       startDownTime = millis();  // get Arduino's current clock time
      }

     characterDone=false; // we're still building a character
     ditOrDah=false;      // the key is still down we're not done with the tone
     delay(myBounce);     // Take a short breath here
     
   if (myNum == 0) {      // myNum will equal zero at the beginning of a character
      myNum = 1;          // This is our start bit  - it only does this once per letter
      }
 }
 
  void keyIsUp() {
   // The decoder does not detect our tone
   // The LEDs on the decoder and Arduino will blink off in unison 
   
   // If we haven't already started our timer, do it now
   if (startUpTime == 0){startUpTime = millis();}
   
   // Find out how long we've gone with no tone
   // If it is twice as long as a dah print a space
   upTime = millis() - startUpTime;
   if (upTime<10)return;
   if (upTime > (averageDah*2)) {    
      printSpace();
   }
   
   // Only do this once after the key goes up
   if (startDownTime > 0){
     downTime = millis() - startDownTime;  // how long was the tone on?
     startDownTime=0;      // clear the 'Key Down' timer
   }
 
   if (!ditOrDah) {   
     // We don't know if it was a dit or a dah yet
      shiftBits();    // let's go find out! And do our Magic with the bits
    }

    // If we are still building a character ...
    if (!characterDone) {
       // Are we done yet?
       if (upTime > dit) { 
         // BINGO! we're done with this one  
         printCharacter();       // Go figure out what character it was and print it       
         characterDone=true;     // We got him, we're done here
         myNum=0;                // This sets us up for getting the next start bit
         }
         downTime=0;               // Reset our keyDown counter
       }
   }
   
   
void shiftBits() {
 
  // we know we've got a dit or a dah, let's find out which
  // then we will shift the bits in myNum and then add 1 or not add 1
  
  if (downTime < dit / 3) return;  // ignore my keybounce
  
  myNum = myNum << 1;   // shift bits left
  ditOrDah = true;        // we will know which one in two lines 
  
  
  // If it is a dit we add 1. If it is a dah we do nothing!
  if (downTime < dit) {
     myNum++;           // add one because it is a dit
     } else {
  
    // The next three lines handle the automatic speed adjustment:
    averageDah = (downTime+averageDah) / 2;  // running average of dahs

    if (averageDah > 1000) averageDah = 1000; // limiting slowest speed to about 3wpm !
   
    dit = averageDah / 3;                    // normal dit would be this
    dit = dit * 2;    // double it to get the threshold between dits and dahs
     }
  }


void printCharacter() {           
  justDid = false;         // OK to print a space again after this

  if (myNum == 511) {
    deleteLastWord();
    return;
  }
  
  // Punctuation marks will make a BIG myNum
  if (myNum > 63) {  
    printPunctuation();  // The value we parsed is bigger than our character array
                         // It is probably a punctuation mark so go figure it out.
    return;              
  }
  decodedCharacter = mySet[myNum]; 
  
  if (currentWordLength < MAXWORD) {
    currentWord[currentWordPos] = decodedCharacter;
    currentWordLength++;
    currentWordPos++;
    lastWordLength = currentWordLength; // this will ensure that lastWordLength is always the length of the most recent word
  } else printSpace();
  sendToLCD();      
}

void printSpace() {
  int wpm;

  if (justDid) return;  // only one space, no matter how long the gap
  justDid = true;       // so we don't do this twice

  currentWordLength = 0;
  currentWordPos = 0;

  wpm = floor(1200 / (float(averageDah/3.0)) );
  ssd1306_char_f6x8(96, 0, "   ");
  doNumber(96,0,wpm);
  
  // We keep track of the average gap between words and bump it up 20 milliseconds
  // do avoid false spaces within the word
  averageWordGap = ((averageWordGap + upTime) / 2) + 20;

  decodedCharacter=' ';            // this is going to go to the LCD 
  
  sendToLCD();         // go figure out where to put it on the display
}

void printPunctuation() {
  // Punctuation marks are made up of more dits and dahs than
  // letters and numbers. Rather than extend the character array
  // out to reach these higher numbers we will simply check for
  // them here. This funtion only gets called when myNum is greater than 63
  
  // Thanks to Jack Purdum for the changes in this function
  // The original uses if then statements and only had 3 punctuation
  // marks. Then as I was copying code off of web sites I added
  // characters we don't normally see on the air and the list got
  // a little long. Using 'switch' to handle them is much better.

  lastWordLength = currentWordLength; // this will ensure that lastWordLength is always the length of the most recent word
  
  switch (myNum) {
    case 71:
      decodedCharacter = ':';
      break;
    case 76:
      decodedCharacter = ',';
      break;
    case 84:
      decodedCharacter = '!';
      break;
    case 94:
      decodedCharacter = '-';
      break;
    case 97:
      decodedCharacter = 39;    // Apostrophe
      break;
    case 101:
      decodedCharacter = '@';
      break;
    case 106:
      decodedCharacter = '.';
      break;
    case 115:
      decodedCharacter = '?';
      break;
    case 246:
      decodedCharacter = '$';
      break;
    case 122:
      decodedCharacter = 's';
      sendToLCD();
      decodedCharacter = 'k';
      break;
    default:
      decodedCharacter = '#';    // Should not get here
      break;
  }
  sendToLCD();    // go figure out where to put it on the display
}

void sendToLCD(){
  uint8_t c,i;

  screenText[LCDline-FIRSTLINE][letterCount] = decodedCharacter;
  
  c = decodedCharacter - 32;
  ssd1306_setpos(letterCount*6,LCDline);
  ssd1306_send_data_start();
  for(i=0;i<6;i++)
  {
    ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+i]));
  }
  ssd1306_send_data_stop();

  letterCount++; 

  if (letterCount > LINELENGTH) {
    newLine(); 
  }
}

void newLine() {
    int scrollNow = 0;
    int oldLine = LCDline;
    int scrolled = 0;
    
    if (LCDline == LASTLINE) {scrollNow = 1; oldLine = LASTLINE-1; scrolled = 1;} else {LCDline++; scrollNow = 0;}
    
    if (scrollNow == 1) scrollUp();
    blankLine(LCDline);
    
    letterCount = 0;


    if (decodedCharacter > ' ') {   
      for (int i = 0; i < currentWordLength; i++) {
        decodedCharacter = currentWord[i];
        sendToLCD();                        
        screenText[oldLine-FIRSTLINE][LINELENGTH-i] = ' '; 
      }  
      ssd1306_setpos(126-(currentWordLength*6),oldLine);
      ssd1306_send_data_start();
      for(int i=0;i<(currentWordLength*6);i++)
      {
        ssd1306_send_byte(0);
      }
      ssd1306_send_data_stop();
    }
}

void blankLine(int line) {
  uint8_t i;
 
  ssd1306_setpos(0,LCDline);
  ssd1306_send_data_start();
  for(i=0;i<128;i++)
  {
    ssd1306_send_byte(0);
  }
  ssd1306_send_data_stop();
}

void scrollUp() {
  int i,j,k,c;

  for(i = 0; i < LASTLINE-FIRSTLINE; i++) {
    for (j=0;j<LINELENGTH+1;j++) {
      screenText[i][j] = screenText[i+1][j];
      c = screenText[i][j] - 32;
      ssd1306_setpos(j*6,i+FIRSTLINE);
      ssd1306_send_data_start();
      for(k=0;k<6;k++)
      {
        ssd1306_send_byte(pgm_read_byte(&ssd1306xled_font6x8[c*6+k]));
      }
      ssd1306_send_data_stop();      
    }
  }  
}

void deleteLastWord() {

  if (lastWordLength < 1) return; 

  if (screenText[LCDline-FIRSTLINE][letterCount-1] == ' ') {
    letterCount--;
  }
  letterCount--;

  for(int i = 0; i < lastWordLength; i++) {
    ssd1306_setpos(letterCount*6,LCDline);
    ssd1306_send_data_start();
    for(int k=0;k<6;k++)
    {
      ssd1306_send_byte(0);
    }
    ssd1306_send_data_stop();    
    letterCount--;
  }
  letterCount++; // we will have gone one further back than the start of the deleted word
  lastWordLength = 0;
  if (letterCount < 0) letterCount = 0;
  justDid = true; // we don't want to stick another space in after deleting
}


Библиотека шрифтов:
 

/*
 * SSD1306xLED - Drivers for SSD1306 controlled dot matrix OLED/PLED 128x64 displays
 *
 * @file: font6x8.h
 * @created: 2014-08-12
 * @author: Neven Boyanov
 * 
 * Hacked by andy jackson to allow two games (originally by webboggles.com) to 
 * fit onto an ATTiny85 at the same time - hence several characters are missing
 * and a couple have been moved to limit the amount of software remapping required
 * to map ASCII values onto locations in this array.
 *
 * Source code available at: https://bitbucket.org/tinusaur/ssd1306xled
 *
 */

// ----------------------------------------------------------------------------

#include <avr/pgmspace.h>

// ----------------------------------------------------------------------------

/* Standard ASCII 6x8 font */
static const uint8_t ssd1306xled_font6x8 [] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
  0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
  0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
  0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
  0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
  0x00, 0x62, 0x64, 0x08, 0x13, 0x23, // %
  0x00, 0x36, 0x49, 0x55, 0x22, 0x50, // &
  0x00, 0x00, 0x05, 0x03, 0x00, 0x00, // '
  0x00, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
  0x00, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
  0x00, 0x14, 0x08, 0x3E, 0x08, 0x14, // *
  0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, // +
  0x00, 0x00, 0x00, 0xA0, 0x60, 0x00, // ,
  0x00, 0x08, 0x08, 0x08, 0x08, 0x08, // -
  0x00, 0x00, 0x60, 0x60, 0x00, 0x00, // .
  0x00, 0x20, 0x10, 0x08, 0x04, 0x02, // /
  0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
  0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, // 1
  0x00, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
  0x00, 0x21, 0x41, 0x45, 0x4B, 0x31, // 3
  0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, // 4
  0x00, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
  0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6
  0x00, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
  0x00, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
  0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, // 9
  0x00, 0x00, 0x36, 0x36, 0x00, 0x00, // :
  0x00, 0x00, 0x56, 0x36, 0x00, 0x00, // ;
  0x00, 0x08, 0x14, 0x22, 0x41, 0x00, // <
  0x00, 0x14, 0x14, 0x14, 0x14, 0x14, // =
  0x00, 0x00, 0x41, 0x22, 0x14, 0x08, // >
  0x00, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
  0x00, 0x32, 0x49, 0x59, 0x51, 0x3E, // @
  0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C, // A
  0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, // B
  0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, // C
  0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, // D
  0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, // E
  0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, // F
  0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A, // G
  0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, // H
  0x00, 0x00, 0x41, 0x7F, 0x41, 0x00, // I
  0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, // J
  0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, // K
  0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, // L
  0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
  0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, // N
  0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, // O
  0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, // P
  0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, // Q
  0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, // R
  0x00, 0x46, 0x49, 0x49, 0x49, 0x31, // S
  0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, // T
  0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, // U
  0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, // V
  0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, // W
  0x00, 0x63, 0x14, 0x08, 0x14, 0x63, // X
  0x00, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
  0x00, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
  0x00, 0x00, 0x7F, 0x41, 0x41, 0x00, // [
  0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55, // 55
  0x00, 0x00, 0x41, 0x41, 0x7F, 0x00, // ]
  0x00, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
  0x00, 0x40, 0x40, 0x40, 0x40, 0x40, // _
  0x00, 0x00, 0x01, 0x02, 0x04, 0x00, // '
  0x00, 0x20, 0x54, 0x54, 0x54, 0x78, // a
  0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, // b
  0x00, 0x38, 0x44, 0x44, 0x44, 0x20, // c
  0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, // d
  0x00, 0x38, 0x54, 0x54, 0x54, 0x18, // e
  0x00, 0x08, 0x7E, 0x09, 0x01, 0x02, // f
  0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // g
  0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, // h
  0x00, 0x00, 0x44, 0x7D, 0x40, 0x00, // i
  0x00, 0x40, 0x80, 0x84, 0x7D, 0x00, // j
  0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, // k
  0x00, 0x00, 0x41, 0x7F, 0x40, 0x00, // l
  0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, // m
  0x00, 0x7C, 0x08, 0x04, 0x04, 0x78, // n
  0x00, 0x38, 0x44, 0x44, 0x44, 0x38, // o
  0x00, 0xFC, 0x24, 0x24, 0x24, 0x18, // p
  0x00, 0x18, 0x24, 0x24, 0x18, 0xFC, // q
  0x00, 0x7C, 0x08, 0x04, 0x04, 0x08, // r
  0x00, 0x48, 0x54, 0x54, 0x54, 0x20, // s
  0x00, 0x04, 0x3F, 0x44, 0x40, 0x20, // t
  0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C, // u
  0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, // v
  0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, // w
  0x00, 0x44, 0x28, 0x10, 0x28, 0x44, // x
  0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C, // y
  0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, // z
  0x14, 0x14, 0x14, 0x14, 0x14, 0x14, // horiz lines
};

// ----------------------------------------------------------------------------

 

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

ua6em пишет:

У меня твой скетч в такой конфигурации заработал:


Я не говорю что он должен заработать. Это, типа, образец.)

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

Green пишет:

ua6em пишет:

У меня твой скетч в такой конфигурации заработал:


Я не говорю что он должен заработать. Это, типа, образец.)

теперь бы научиться разделять нулевой таймер тот что с миллис, раз шим на 0 возможен значит можно

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

С утра не задалось, пните где косяк?
 

// analogWrite(PB3,i);

volatile uint8_t i=1;
volatile uint8_t j;

ISR (TIMER1_COMPB_vect) {
  j++;
  if (j == 1) {
    i+=2;
    cli();
    OCR1B = i;
    sei();
  }
}


void setup() {
  DDRB = (1 << PB3) | (1 << PB1);
  OCR1B = 1;
  OCR1C = 255;
  GTCCR |= (1 << PWM1B) | (1 << COM1B0);
  TCCR1 |= (7 << CS10); // CK/64 = 1Khz
//  TIMSK = 1 << OCIE1B;
}

void loop() {
  delay(15);
    cli();
   i++;
    OCR1B = i;
    sei();  
    analogWrite(PB1,i);   
}

А так работает!
 


// analogWrite(PB3,i);

volatile uint8_t i = 1;
volatile uint8_t j = 1;

ISR (TIMER1_COMPB_vect) {
  j+=16;
  if (j == 1) {
    i ++;
    cli();
    OCR1B = i;
    sei();
    analogWrite(PB1, i);
  }
}


void setup() {
  DDRB = (1 << PB3) | (1 << PB4) | (1 << PB1);
  OCR1B = 1;
  OCR1C = 255;
  GTCCR |= (1 << PWM1B) | (1 << COM1B0);
  TCCR1 |= (7 << CS10); // CK/64 = 1Khz
  TIMSK |= 1 << OCIE1B;
}

void loop() {
  /*
    delay(15);
    cli();
    i++;
    OCR1B = i;
    sei();
    analogWrite(PB1,i);
  */
}

 

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

cli() и  sei() внутри прерывания? зачем?

 

ua6em пишет:

пните где косяк?

j случаем не надо обнулять при срабатывании прерывания?

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

b707 пишет:

cli() и  sei() внутри прерывания? зачем?

 

ua6em пишет:

пните где косяк?

j случаем не надо обнулять при срабатывании прерывания?

мне сейчас точное значение без разницы, идея - заставить PWM на 4-х пинах не ломая возможности стандартного ядра, на системном 0 видимо паразитируя на оном, второе непонятно почему не работает через прерывание, если в loop то всё пучком

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

то есть то что у тебя условие J==1 сработает один раз - это так и надо?

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

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

b707 пишет:

то есть то что у тебя условие J==1 сработает один раз - это так и надо?

почему один раз, это же uint8_t если увеличивать на 1, то изменяется в цикле 0-255 и так по кругу

PS заработало, если не портить регистры

  GTCCR |= (1 << PWM1B) | (1 << COM1B0);
  TCCR1 |= (7 << CS10); // CK/64 = 1Khz
  TIMSK |= 1 << OCIE1B;

 

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

простой индикатор питающего напряжения:
 

// ATMEL                                ATtiny 25/45/85
//                                           +-\/-+
//             !RESET PCINT5 5/A0 (D 5) PB5 1|    |8  Vcc
//  XTAL1 CLKI !OC1B  PCINT3 3/A3 (D 3) PB3 2|    |7  PB2 (D 2) 2/A1 PCINT2 USCK SCK T0 INT0 SCL  
//  XTAL2 CLKO  OC1B  PCINT4 4/A2 {D 4) PB4 3|    |6  PB1 (D 1) pwm1 PCINT1 MISO DO  OC0B AIN1
//                                      GND 4|    |5  PB0 (D 0) pwm0 PCINT0 MOSI DI  OC0A AIN0 SDA AREF
//                                           +----+


#define ADC     _SFR_IO16(0x04)

volatile bool leds = true;
uint16_t divs = 1; // программный делитель
volatile uint16_t clocks;
uint16_t tiks = 0;
volatile uint16_t work_time = 5;
volatile uint16_t period = 5;

ISR (TIMER1_COMPA_vect) {
  clocks++;
  if (clocks == divs) {
    clocks = 0;
    tiks++;
    if (tiks >= (leds ? work_time : period)) {
      tiks = 0;
      leds = !leds;
      digitalWrite(PB1, leds);
    }
  }
}


uint16_t readVcc() {
  // Описание здесь - <a data-cke-saved-href="https://blog.unlimite.net/?p=25" href="https://blog.unlimite.net/?p=25" rel="nofollow">https://blog.unlimite.net/?p=25</a>
  // Read 1.1V reference against AVcc
  // set the reference to Vcc and the measurement to the internal 1.1V reference

#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif

  delay(75); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Start conversion
  while (bit_is_set(ADCSRA, ADSC)); // measuring

/*
  uint8_t low  = ADCL; // must read ADCL first - it then locks ADCH
  uint8_t high = ADCH; // unlocks both
  uint16_t result = (high << 8) | low;
*/
  uint16_t result = ADC;

  result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
  return result; // Vcc in millivolts
}

void setup() {
  DDRB = (1 << PB1);
  OCR1A = 83;
  OCR1C = 165;
  TCCR1 = (1 << PWM1A) | (15 << CS10); // |(1<<COM1A0)2)|(1<<CS11);
  TIMSK = 1 << OCIE1A;
  digitalWrite(PB1, leds);
}

void loop() {
  long vcc = readVcc() / 1000;
  work_time = 6 - vcc;
  period = 5 * vcc;
}

С оверсэмлингом до 14 бит (не проверялось)
 

// ATMEL                                ATtiny 25/45/85
//                                           +-\/-+
//             !RESET PCINT5 5/A0 (D 5) PB5 1|    |8  Vcc
//  XTAL1 CLKI !OC1B  PCINT3 3/A3 (D 3) PB3 2|    |7  PB2 (D 2) 2/A1 PCINT2 USCK SCK T0 INT0 SCL
//  XTAL2 CLKO  OC1B  PCINT4 4/A2 {D 4) PB4 3|    |6  PB1 (D 1) pwm1 PCINT1 MISO DO  OC0B AIN1
//                                      GND 4|    |5  PB0 (D 0) pwm0 PCINT0 MOSI DI  OC0A AIN0 SDA AREF
//                                           +----+

#define ADC     _SFR_IO16(0x04)

volatile bool leds = true;
uint16_t divs = 1; // программный делитель
volatile uint16_t clocks;
uint16_t tiks = 0;
volatile uint16_t work_time = 5;
volatile uint16_t period = 5;

ISR (TIMER1_COMPA_vect) {
  clocks++;
  if (clocks == divs) {
    clocks = 0;
    tiks++;
    if (tiks >= (leds ? work_time : period)) {
      tiks = 0;
      leds = !leds;
      digitalWrite(PB1, leds);
    }
  }
}


void setup() {
  //Serial.begin(115200);

  DDRB = (1 << PB1);
  OCR1A = 83;
  OCR1C = 165;
  TCCR1 = (1 << PWM1A) | (15 << CS10); // |(1<<COM1A0)2)|(1<<CS11);
  TIMSK = 1 << OCIE1A;
  digitalWrite(PB1, leds);
}

void loop() {
  long vcc = ((long)(1100 * 16368) / Vbg())/1000 ;
  //Serial.println (Vop,3);                   //
  work_time = 6 - vcc;
  period = 3 * vcc;
}


int Vbg() {
  //ADMUX = (1<<REFS0)|(0<<REFS1)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0); //Atmega-328P
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
  ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
  ADMUX = _BV(MUX3) | _BV(MUX2);
#else
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif

  long buffersamp = 0;
  for (int n = 0x0; n <= 0xff; n++ ) {
    ADCSRA |= (1 << ADSC) | (1 << ADEN);        // Starts a new conversion
    while (bit_is_set(ADCSRA, ADSC));
    buffersamp += ADC;
  }
  buffersamp >>= 4;                           // 16368 full scale 14bit
  ADCSRA &= ~(1 << ADEN);                     // отключаем АЦП
  return buffersamp;
}

 

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

Опять ADCH, ADCL, магические цифры... Ужос.

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

Green пишет:

Опять ADCH, ADCL, магические цифры... Ужос.

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

PS "Академическим виделся текст, а на поверку про СЕКС " BLINK )))

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

ua6em 

#define ADC     _SFR_IO16(0x04)

#define ADC     _SFR_MEM16(0x78)

ADC объявлен именно так !

Заряд надо по яркости светодиода оценивать ?

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

Komandir пишет:

ua6em #define ADC     _SFR_IO16(0x04)

ADC объявлен именно так !

Заряд надо по яркости светодиода оценивать ?

я жеж лётчик по правилам визуального пилотирования, пока всё норм короткие вспышки, иначе длинные, параллельно можно поставить зуммер  который как только напряжение достигнет критического уровня звучит постоянно... (но это надо дописать)

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

Странно! На макете всё работает как и задумывалось, а в эмуляторе - нет!
 

// BLINK для ATtiny85
// LED_BUILTIN на пине D1
// ATMEL                               ATtiny 25/45/85
//                                          +-\/-+
//             !RESET PCINT5 5/A0 (D5) PB5 1|    |8  Vcc
//  XTAL1 CLKI !OC1B  PCINT3 3/A3 (D3) PB3 2|    |7  PB2 (D2) 2/A1 PCINT2 USCK SCK T0   INT0 SCL  
//  XTAL2 CLKO  OC1B  PCINT4 4/A2 (D4) PB4 3|    |6  PB1 (D1) pwm1 PCINT1 MISO DO  OC0B AIN1
//                                     GND 4|    |5  PB0 (D0) pwm0 PCINT0 MOSI DI  OC0A AIN0 SDA AREF
//                                          +----+


enum Prescalers_1 {
  //T1CK
  PRESCALER_1 = 1,
  PRESCALER_2 = 2,
  PRESCALER_4 = 3,
  PRESCALER_8 = 4,
  PRESCALER_16 = 5,
  PRESCALER_32 = 6,
  PRESCALER_64 = 7,
  PRESCALER_128 = 8,
  PRESCALER_256 = 9,
  PRESCALER_512 = 10,
  PRESCALER_1024 = 11,
  PRESCALER_2048 = 12,
  PRESCALER_4096 = 13,
  PRESCALER_8192 = 14,
  PRESCALER_16384 = 15
};

void setup() {

  uint8_t prescaler1 = PRESCALER_16384;
  DDRB = (1 << PB1);
  OCR1A = 127;
  OCR1C = 255;
  TCCR1 = prescaler1 |(1 << PWM1A) | (1 << COM1A0);// | (1 << CS13) | (1 << CS12) | (1 << CS11)| (1 << CS10);

}

void loop() {
}

 

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

вот такие строчки никогда не используй в ардуино

DDRB = (1 << PB1);

PB1 может означать совсем не то, что ты думаешь.

Порт у тебя и так выбран макросом DDRB, поэтому правильно так

DDRB = (1 << 1);

 

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

Интересно, а что РВ1 может ещё означать кроме того что определено в главном макросе описания МК?

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

nik182 пишет:
Интересно, а что РВ1 может ещё означать кроме того что определено в главном макросе описания МК?

понятно, что там именно то, что в макросе :)  вопрос в том,  что там?

Была тут тема, когда человек тоже писал 

DDRx = (1 << Px5);

а потом вдруг оказалось, что в Px5 внутри вовсе и не 5, а совсем иное значение.

Но похоже это не к АВР относилось, сейчас посмотрел исходники ардуино - для АВР вроде значения всегда соответвуют номеру бита.

А например в СТМ32 попытка создать маску бита подобным образом не сработает, там в макросах типа PA2 или PB10 зашит не номер бита, а порядковый номер GPIO

 

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

похоже этот гвоздь не в ту стену, в эмуляторе как не работало так и не работает )))

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

Вот только PB1 означает физику, что в общем то, не имеет смысла.

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

Green пишет:

Вот только PB1 означает физику, что в общем то, не имеет смысла.

а как надо?

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

По красивому, вначале расписываете логику, и с ней уже оперируете.
 

#define LED  PB1
#define LED_DIR  DDRB
#define LED_PORT  PORTB

LED_DIR |= 1<<LED;
LED_PORT ^= 1<<LED;

 

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

b707 пишет:

nik182 пишет:
Интересно, а что РВ1 может ещё означать кроме того что определено в главном макросе описания МК?

понятно, что там именно то, что в макросе :)  вопрос в том,  что там?

Была тут тема, когда человек тоже писал 

DDRx = (1 << Px5);

а потом вдруг оказалось, что в Px5 внутри вовсе и не 5, а совсем иное значение.

Но похоже это не к АВР относилось, сейчас посмотрел исходники ардуино - для АВР вроде значения всегда соответвуют номеру бита.

А например в СТМ32 попытка создать маску бита подобным образом не сработает, там в макросах типа PA2 или PB10 зашит не номер бита, а порядковый номер GPIO

 


Это да с STM в таком виде не сработает. Но там есть специальные дефы на номер и макросы перевода номера бита в значение и обратно. Так что может всё получится, если знать какие дефы или макросы применять.

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

Green пишет:

По красивому, вначале расписываете логику, и с ней уже оперируете.#define LED PB1

#define LED_DIR  DDRB
#define LED_PORT  PORTB

LED_DIR |= 1<<LED;
LED_PORT ^= 1<<LED;

конечно читабельней но в эмуляторе всё одно не работает )))

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

Уличный термометр, attiny25/45/85 взято здесь:

 

#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;
}