уменьшение размера прошивки)

whoim
Offline
Зарегистрирован: 03.11.2011

 Очень хочется запихнуть проект в tiny13, у нее всего килобайт памяти. Пока выходит 1174 байта..

Чем можно заменить digitalRead на си? Пробовал bitRead(PORTB, X) - не работает. Есть ли возможность построить низкочастотный (100 - 500гц) ШИМ без analogWrite? Больно много кушает..

софтинка как то так смотрится


//cars lamp day light

#define LAMP1 0
#define LAMP2 1
#define BLINK 2
#define ACC 3
#define BAD 4
#define MAX 100

//vars
boolean state = false;
long prt;
long offtime;
void setup() {
  DDRB = B00000011;
  PORTB = B00011100;
}

void loop() {
 
 if (prt < millis() - 100) {
 
   prt = millis();
   
   if (!state && digitalRead(ACC)==LOW && digitalRead(BAD)!=LOW) {
     state = true;
     lamp_on();
   }
  
   if (state)
   if (digitalRead(ACC)!=LOW || digitalRead(BAD)==LOW) {
     if (offtime > millis() - 5000) {
       state = false;
       lamp_off();
     }
     else
       offtime = millis();
   }
 }
}

void lamp_on() {
 /*for (int x=0; x <= MAX; x++) {
   analogWrite(LAMP1, x);
   analogWrite(LAMP2, x);
   delay(10);
 } */
 bitSet(PORTB,LAMP1);
 bitSet(PORTB,LAMP2);
}

void lamp_off() {
 /*for (int x=MAX; x >= 0; x--) {
   analogWrite(LAMP1, x);
   analogWrite(LAMP2, x);
   delay(10);
 } */
 bitClear(PORTB,LAMP1);
 bitClear(PORTB,LAMP2);
}

 

step962
Offline
Зарегистрирован: 23.05.2011

1.  Что-то не нашел у вас неработающий bitRead (ну хотя бы закомментаренный).

2. Что значит - "не работает"?

3. Чего "больно много кушает"?

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Почитайте http://arduino.ru/Tutorial/Upravlenie_portami_cherez_registry

Не совсем ясно зачем вам вообще этот bitSet нужен

#define LAMP1 B00000001
#define LAMP2 B00000010
.....
PORTB= LAMP1 & LAMP2; // включили сразу оба диода
PORTB=0; // выключили все пины на порте B,
.......
if(PORTB & B00000010){
  что-то делаем если на первом пине порта B (нумерация с нуля) есть логическая еденица
}
...

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

step962
Offline
Зарегистрирован: 23.05.2011

leshak пишет:

 

.......
if(PORTB & B00000010){
  что-то делаем если на первом пине порта B (нумерация с нуля) есть логическая еденица
}
...

Для чтения данных рекомендуется использовать не регистр PORTx, а другой - специально предназначенный для чтения - PINx (кстати, читать из него можно даже если соответствующий пин настроен как выход). Почитать об этом можно, например, здесь, либо - поподробнее - у diHALT'а.

whoim
Offline
Зарегистрирован: 03.11.2011

 Огромное спасибо! Это - именно то что мне надо было. 

>Что-то не нашел у вас неработающий bitRead (ну хотя бы закомментаренный).

Сейчас там его нет, конечно. Пробовал вместо digitalRead конструкцию if bitRead(PORTB, 5) == 1

>Чего "больно много кушает"?

памяти )))

whoim
Offline
Зарегистрирован: 03.11.2011

 Комиксы у дихалта убили))

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Есть ли возможность построить низкочастотный (100 - 500гц) ШИМ без analogWrite? 

Теоретически возможно настроить на 122, 244, 488 Гц (при тактовой частоте процессора 16 МГц, на 488 Гц штатные ШИМы работают). Вам любая частота из этого диапазона подойдет или несколькими частотами оперировать хоцца?

whoim
Offline
Зарегистрирован: 03.11.2011

 да любая, мне лампочкой на 12в рулить, там от 100гц побарабану. Таймер? И инвертировать булевую?

Таймер на тини13/тини45 надо изучать..

whoim
Offline
Зарегистрирован: 03.11.2011

 Тактовая кстати 8мгц, камень - тини45/тини13 )

whoim
Offline
Зарегистрирован: 03.11.2011

 Покажите, пожалуйста, на примере этой конструкции:

#define ACC 3 //вход зажигания
#define BAD 4 //входы запрета if (state) { if (digitalRead(ACC)!=LOW || digitalRead(BAD)==LOW) { if (digitalRead(BAD)==LOW)

if (PINB2 == LOW) компилится, но не срабатывает..

step962
Offline
Зарегистрирован: 23.05.2011

Ну, для tiny я ШИМ не настраивал, проверить свои мысли в железе не могу, так что давайте вместе.

Загружаем Datasheet (у меня - на ATtiny13), в разделе "Peripheral Features" читаем:

Цитата:
– One 8-bit Timer/Counter with Prescaler and Two PWM Channel 
Уже хорошо - необходимая нам возможность имеется. Правда есть одно сомнение, которое можно развеять лишь экспериментом: поскольку таймер/счетчик всего лишь "one", существует риск того, что при программировании из под Arduino IDE последняя будет пытаться навесить на таймер/счетчик свою лабуду, необходимую для поддержки функций времени, и сформирует ISR для того же вектора прерывания (TIMER0_OVF_vector), который, возможно, потребуется и нам... Так что на всякий случай ищите хотя бы AVR Studio.

Для настройки ШИМ-функций одного из каналов таймера/счетчика (A или B) необходимо прежде всего выбрать режим работы таймера/счетчика (биты WGM2...WGM0 в регистрах TCCR0A и TCCR0B). Для необходимого нам Fast PWM эти биты необходимо установить в 3 или 7 - т.е. бит WGM2 (третий в регистре TCCR0B) на этапе первого запуска ШИМа не имеет значения (хотя и весьма важен - (табл. 11-3 в разделе 11.9.1 на стр. 72 моего даташита)).

Биты WGM1 и WGM0 - это соответственно первый и нулевой биты регистра TCCR0A. В этом же регистре седьмой и шестой биты (COM0A1 и COM0A0) отвечают за настройку выхода. Нам важно его включить - то есть любая комбинация, кроме 00 (табл. 11-3 в разделе 11.9.1 на стр. 70) . Пусть будет "11" ("Set OC0A on Compare Match, clear OC0A at TOP").

 

TCCR0A = 0xC3; //b11000011

Теперь биты регистра TCCR0B:

седьмой и шестой имеют значение лишь в не-ШИМ-режимах.

пятый и четвертый - не используются

третий - WGM2 - установим в 0, но возьмем на заметку для дальнейшей работы

три первых - настройка предделителя и источника тактового сигнала - запишем сюда максимальное значение для предделителя (самого медленного ШИМа) при работе от внутреннего тактового генератора (который и АЛУ тактирует).

TCCR0B = 0x17; //b00010101
 

TIMSK0 - регистр-маска прерываний. Не трогаем - я еще не программировал ШИМов, но по идее - при выполненных нами настройках, схема таймера/счетчика должна напрямую дергать ногу OCn. Что такое OCn? Пин, на который соответствующий ШИМ-канкл (A/B) выводит свой сигнал. В даташите на стр. 2 (раздел 1 - распиновка) видим, что дополнительная функция OC0A доступна на пине 5, а OC0B - на пине 6. К этому пину и подключаем нагрузку, которой необходимо управлять.

Итак:

setup() {
  TCCR0A = 0cC3;
  TCCR0B = 0x17;
}

loop() {
}

 

Все? Нет - забыли задать скважность. В канале A за это отвечает регистр OCR0A. Диапазон значений от 0 (скважность 100%) до 255 (скважность 0%). Для теста устанавливаем какую-то постоянную величину в setup(), при программном управлении - меняем значение либо в любой момент (тогда могут получаться отдельные импульсы со случайной скважностью), либо в ISR (вот тут и получаем потенциальную коллизию с ардуиновской системой отсчета времени).

Окончательно:

setup() {
  TCCR0A = 0cC3;
  TCCR0B = 0x17;
  OCR0A = 127;
}

loop() {

}

 Хотя, какое окончательно - это только начало бодания. :)

Дальше ваш ход.

whoim
Offline
Зарегистрирован: 03.11.2011

 Все понял, AVR студио стоит, протеус стоит, если что и тини13 лежит - будем пробовать )

Вечером, с работы прибуду - раз пять перечитаю и приступлю. Пост - в мемориз, однозначно (в смысле, в копилку знаний).

whoim
Offline
Зарегистрирован: 03.11.2011

 step962, по второму вопросу - как аналогично (PINB & B00000001) проверить на нужном выводе низкий уровень?

UPD возможно, !(PINB & B00000001)

step962
Offline
Зарегистрирован: 23.05.2011

 Ну так

if(!(PINB & B00000001))

даст нужную проверку. Операцией "&" мы обнуляем все биты, кроме проверяемого, а дальше, если результат равен нулю, то имеем низкий уровень, если не равен - высокий.

Для одного бита можно писать

if(PINB & (1<<x)) для проверки на HIGH
if(!(PINB & (1<<x))) для проверки на LOW

где x - номер проверяемого бита. Оно дидактичней как-то получается, а с учетом того, что в сях для мк определено море констант, обеспечивающих более удобный доступ к нужным битам регистров, то и тем более рекомендуемо.

Например, настройка упоминавшихся битов WG2-WG0 и предделителя (правда, не на ту конфигурацию, что рассматривалась ранее):

TCCR0A = (1<<COM0B1) | (1<<WGM00) | (1<<WGM01);
TCCR0B = (1<<WGM02) | (1<<CS00);

 и все сразу так понятненько становится ;)

(в папке arduino сходить в hardware\tools\avr\avr\include\avr и ознакомиться с имеющимися там хидерами, например, с iom328p.h)

whoim
Offline
Зарегистрирован: 03.11.2011

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

Мало времени на ардуино остается.. час вечером и попаять и пописать..

whoim
Offline
Зарегистрирован: 03.11.2011

 

if (!state && !(PORTB & (1<<ACC)) && (PORTB & (1<<BAD)))

Не работает

if (!state && digitalRead(ACC)==LOW && digitalRead(BAD)!=LOW)

Работает

ATTINY45 в протеусе. Замена PORTB на PINB ничего не меняет..

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

Не работает

Работает

А что такое BAD и ACC? В смысле - какие значения имеют эти константы? Скорее всего это номера пинов Ардуины. Предположим на секунду, что BAD равен 14. Или хотя бы 8.

Операция 1<<8 сдвигает биты в байте (порту) на 8 позиций влево, т.е. самый правый бит уходит за левую границу байта (порта). Что-то не сходится, правда? Может быть оперируя пинами мк напрямую, а не через функции Ардуино, и номера пинов брать атмеловские, а не ардуиновсие? Как вам такая идея? ;)

В общем - найдите картинку с распиновкой мк в соответствующей Ардуине и переведите BAD/ACC в номера битов соответствующих портов. Тот же 8-й пин - в PB0 (нулевой бит порта B), а 14-й (это он у нас 0-й аналоговый?)- в PC0 (нулевой бит порта C).

И будет вам счастье... Возможно.

 

ЗЫ: digitalRead и прочие analogWrite, прежде чем обратиться к физическому выводу мк, как раз этим самым ремаппингом и занимаются.

whoim
Offline
Зарегистрирован: 03.11.2011

ACC=3, BAD=4.

http://www.atmel.com/Images/2586S.pdf

ACC=PB3, BAD=PB4

Совпадение пинов с ардуиновскими - плюс разработчикам кода аттини для ардуино )

в чем то другом дело..

whoim
Offline
Зарегистрирован: 03.11.2011

 pins_arduino.h

/*
  pins_arduino.c - pin definitions for the Arduino board
  Part of Arduino / Wiring Lite

  Copyright (c) 2005 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  $Id: pins_arduino.c 565 2009-03-25 10:50:00Z dmellis $

  Modified 28-08-2009 for attiny84 R.Wiersma
  Modified 09-10-2009 for attiny45 A.Saporetti
*/

#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <avr/pgmspace.h>

// ATMEL ATTINY45 / ARDUINO
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2)  Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

#define digitalPinToPCICR(p)    ( ((p) >= 0 && (p) <= 4) ? (&GIMSK) : ((uint8_t *)0) )
#define digitalPinToPCICRbit(p) ( PCIE )
#define digitalPinToPCMSK(p)    ( ((p) <= 4) ? (&PCMSK) : ((uint8_t *)0) )
#define digitalPinToPCMSKbit(p) ( (p) )

#ifdef ARDUINO_MAIN

// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing) tiny45 only port B 
const uint16_t PROGMEM port_to_mode_PGM[] = {
	NOT_A_PORT,
	NOT_A_PORT,
	(uint16_t) &DDRB,
};

const uint16_t PROGMEM port_to_output_PGM[] = {
	NOT_A_PORT,
	NOT_A_PORT,
	(uint16_t) &PORTB,
};

const uint16_t PROGMEM port_to_input_PGM[] = {
	NOT_A_PIN,
	NOT_A_PIN,
	(uint16_t) &PINB,
};

const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
	PB, /* 0 */
	PB,
	PB,
	PB,
	PB, 
	PB, // 5

};

const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
	_BV(0), /* 0, port B */
	_BV(1),
	_BV(2),
	_BV(3), /* 3 port B */
	_BV(4),
	_BV(5),

};

const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
	TIMER0A, /* OC0A */
	TIMER0B,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
	NOT_ON_TIMER,
};

#endif

#endif

 

step962
Offline
Зарегистрирован: 23.05.2011

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

Если не ошибаюсь, в Arduino режим ввода/вывода пинов автоматически устанавливается на вывод. Если соответствующая библиотека в погоне за миниатюрностью кодов выключена, то состояние пина может оказаться не тем, что нам надо. Поэтому настроим пины PB3/PB4 на выход явно. Для этого в соответствующие биты регистра направления DDRx (в нашем случае DDRB) записываем единички (на всякий случай не трогая все остальные биты - поэтому через or):

DDRB |= b00011000;

Повторяем попытку.

 

ЗЫ: Тьфу ты блин. На вывод у нас 0-й и 1-й биты. 3-й и 4-й - на ввод. Выполняем настройку выводов в два присеста - сначала выводы, потом вводы:

DDRB |= b00000011;

DDRB &= ~b00011000; (то же самое, что и DDRB &= b11100111;)
 

whoim
Offline
Зарегистрирован: 03.11.2011

Вообще я четко указываю состояние пинов и режим так:

DDRB = B00000011;

PORTB = B00011100;

0 и 1 - вывод ШИМ, 2,3,4 - входа, срабатывают по LOW.

Ну то есть видимо и не в этом дело..

step962
Offline
Зарегистрирован: 23.05.2011

 Как обычно, если есть проблема, то самый лучший способ ее решения - по частям.

1-й вопрос: работает ли ШИМ? Проверить можно, подключив к соответствующему выводу светодиод.

2-й вопрос: правильно ли считываются состояния входов? проверяем периодическим выводом значения PINB в Serial.

 

Я тут между делом проверку ШИМа наваял:

volatile long ms10;
volatile int cntr;
long tmillis,tms10=0;
char flip;

void setup() {                  
  // мигаем стандартным светодиодом.
  // На большинстве плат Arduino он подключен к 13-му выводу:
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  flip = 0;
  ms10 = 0;
  setup_FPWM2();
}

void setup_FPWM2() {
// настройка быстрого ШИМ
  Serial.println("Setting up PWM2 Canal A");
  // Включаем нужный нам режим таймера/счетчика - нормальный
  TCCR2A = 3; //Fast PWM | TOP = 0xFF(но может быть и 7: TOP = OCR2A)
  // COM1:COM0=2 - на OC2A уровень LOW при значениях TCNT2 между OCR2A и TOP
  // COM1:COM0=3 - на OC2A уровень HIGH при значениях TCNT2 между OCR2A и TOP
  TCCR2A |= 0x80;
  //CS22:CS20 = 111: предделитель = 1024
  TCCR2B = 7;
  // отслеживаем прерывания по сравнению для канала A (OCIE2A) и по переполнению (TOIE2)
  TIMSK2 |= (1<<OCIE2A)+(1<<TOIE2);
  sei();
}

ISR(TIMER2_COMPA_vect) {
  ms10++;
  PORTB = PINB & 0b11011111;
}
ISR(TIMER2_OVF_vect) {
  ms10++;
  PORTB = PINB | 0b00100000;
}

void loop() {
  if(flip ) {  // увеличение
    if (OCR2A==255) {
      Serial.print("ms10: "); Serial.print(ms10);
      Serial.print(", TCCR2A: "); Serial.print(TCCR2A,HEX);
      Serial.print(", TCCR2B: "); Serial.print(TCCR2B,HEX);
      Serial.print(", OCR2A: ");  Serial.println(OCR2A,HEX);
      flip = !flip;
    }      
    else OCR2A += 1;
  }
  else { // уменьшение
    if (OCR2A==0) {
      Serial.print("ms10: "); Serial.print(ms10);
      Serial.print(", TCCR2A: "); Serial.print(TCCR2A,HEX);
      Serial.print(", TCCR2B: "); Serial.print(TCCR2B,HEX);
      Serial.print(", OCR2A: ");  Serial.println(OCR2A,HEX);
      flip = !flip;
    }      
    else OCR2A -= 1;
  }
  delay(10);
}

Яркость штатного светодиода довольно плавно меняется туда-сюда - так что ШИМ настраивается. Конечно это второй таймер/счетчик, а не нулевой, но идеология у них идентичная, второй от нулевого по большому счету лишь наличием асинхронного режима отличается. 

whoim
Offline
Зарегистрирован: 03.11.2011

 ШИМом займусь на днях, буду перечитывать и вникать в этот топик. вопрос как бы не срочный, на тестах analogWrite спасает - вопрос в "своем" шиме только чтобы уменьшить прошивку.

Больше сейчас зациклен на проверке состояния пинов. Сдается мне, на "стандартной" атмеге8 / 328 все будет работать, а на АтТини есть какой то нюанс..

Соберусь с силами попозже - буду пробовать, отпишусь. Спасибо!

whoim
Offline
Зарегистрирован: 03.11.2011

 В общем то, с ШИМом под аттини в иде непрошло. http://my.jetscreenshot.com/1474/20120309-idei-41kb

leshak
Offline
Зарегистрирован: 29.09.2011

 На всякий случай (вдруг не видели).

Ссылочка code.google.com/p/arduino-tiny/

реализация базовых arduino библиотек, под attinny.

Если не взять, то хоть "подсмотреть" в них. Ту же работу с PWM.

whoim
Offline
Зарегистрирован: 03.11.2011

 Да, не встречал. Точнее, работал с более ранней - точнее, другой веткой проекта.
Просто заработать - не заработало, буду подсматривать )

step962
Offline
Зарегистрирован: 23.05.2011

 Ну. с учетом того, что ATtiny13 обладает одним-единственным таймером/счетчиком с номером 0, регистры типа TCCR2A, TIMSK2 и протчая (а также вектора прерываний с индексами "2") в соответствующем хидере не прописаны. Все двойки необходимо заменить нуликами. Поток ругани должен уменьшиться.

whoim
Offline
Зарегистрирован: 03.11.2011

 

  TCCR0A = 3;
  TCCR0A |= 0x80;
  OCR0A = 127;
  TIMSK |= (1<<OCIE0A)+(1<<TOIE0);

скомпилировалось

whoim
Offline
Зарегистрирован: 03.11.2011

 Догадался сам))))

whoim
Offline
Зарегистрирован: 03.11.2011

 Завелось. Но только..

http://my.jetscreenshot.com/1474/20120309-qbpo-82kb

похоже, при OCR0A = 0; у нас наоборот.. 100% ШИМ )

whoim
Offline
Зарегистрирован: 03.11.2011

 И теперь надо научится отключать таймер) Я так понимаю, TCCR0A = 0; его отключит?

whoim
Offline
Зарегистрирован: 03.11.2011

whoim пишет:

 Завелось. Но только..

http://my.jetscreenshot.com/1474/20120309-qbpo-82kb

похоже, при OCR0A = 0; у нас наоборот.. 100% ШИМ )

Очень торможу. Брал сигнал оссицилографу с затвора мосфета, он туда инвертированным приходит.

Фронта местами грустные конечно.. С МК - нормальные, с транзисторов - жуть..

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 И теперь надо научится отключать таймер) Я так понимаю, TCCR0A = 0; его отключит?

Нет, это его убьет. ;)

После такого насилия схема таймера/счетчика станет работать в свем простейшем - "нормальном" - режиме. Именно как таймер - каждые 256 (или 256*значение предделителя) будет происходить переполнение счетчика и генерация прерывания TOV0.

Чтобы отключить ШИМ по каналу A, достаточно обнулить 7-й и 6-й биты:

TCCR0A |= 0x3F;

При таком варианте отключения можно продолжать работать с ШИМом по каналу B (если он был настроен и использовался до этого).

Чтобы отключить прерывания - сбросить соответствующие биты регистра TIMSK0.

Вообще-то таймер очень живуч: чтобы остановить его полностью, придется перейти в такой режим энергопотребления, в котором останавливается осциллятор портов ввода/вывода ("ADC Noise Reduction" или - о ужас - "Power-Down"). Но во всех этих режимах останавливается и осциллятор ЦПУ - программа стоит и ждет пробуждения. А оно нам надо?

Правда, вход через черную дверь таки есть. И даже два.

1) Если перевести таймер на работу от внешнего источника тактового сигнала (CS2:CS0 в регистре TCCRB0 установить в 110 или 111), а потом выключить этот источник, то таймер замрет, а все остальные схемы микроконтроллера продолжат трудиться.

2) Если упомянутые биты сбросить полностью (CS2:CS0 = 000), то таймер перестанет принимать тактовый сигнал как от внутреннего осциллятора, так и от внешнего источника. Результат - остановка схемы.

Так что выбирайте, что больше всего подходит конкретной задаче. 

whoim
Offline
Зарегистрирован: 03.11.2011

Понял, спасибо! Я так понимаю, что ардуиновские millis и delay используют этот таймер? Ими пора прекратить пользоваться?

whoim
Offline
Зарегистрирован: 03.11.2011

 Научите еще как рассчитать частоту PWM (таймера?)

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Научите еще как рассчитать частоту PWM (таймера?)

Ну это - в простейшем случае - как два пальца об асфальт.

Берем тактовую частоту микроконтроллера (если мы питаем таймер/счетчик от внутреннего осциллятора). Делим ее на запрограммированное нами значение предделителя, затем еще на 256 (разрядность счетчика). Получаем частоту PWM.

Например, минимальная частота PWM для стандартной ардуины:

16 МГц / 1024 (максимальное значение предделителя) / 256 =  61,03 Гц

А если предделитель на 128 настроен, то получаем 488 Гц - частоту ардуиновских ШИМ-ов.

whoim
Offline
Зарегистрирован: 03.11.2011

 

TCCR0A =
три первых - настройка предделителя и источника тактового сигнала - запишем сюда максимальное значение для предделителя (самого медленного ШИМа) при работе от внутреннего тактового генератора (который и АЛУ тактирует).

понял

whoim
Offline
Зарегистрирован: 03.11.2011

 Суть расчета понял. Как правильно загнать нужное мне в регистры - не могу понять...

Частота МК 8 000 000
Надо что то около 10 000

8000000/4/256 = ~8кгц, нормально. Как мне задать делитель 4?

step962
Offline
Зарегистрирован: 23.05.2011

 Если открыть даташит на ATtiny13 (ведь мы о ней говорим?), то в главе 11 можно вычитать, что прескалер в таймере этого камня может настраиваться на 1,8,64,256,1024. Четверки в этом списке нет...

Печально? Да. Но не смертельно.

Вспоминаем, что выбирая режим работы 3 (fast PWM), мы игнорировали еже один режим работы - 7. Который тоже fast PWM. Зачем два одинаковых режима? А они не совсем одинаковые. Если в режиме 3 сброс счетчика происходит при попытке добавить единицу к 255 (т.е. цикл 256 тиков), то в режиме 7 сброс счетчика происходит, когда его значение сравняется с значением в регистре OCRA.

Поэтому:

- если установлен режим 7 (т.е. дополнительно установлен бит 3 в регистре TCCR0B)

- если предделитель настроен на 8 (биты 2,1,0 в регистре TCCR0B усановлены в 010)

- в регистр OCR0A загружено значение 124

то получаем частоту на выходе не 4 кГц, а 8 (8000000/4/125).

А если в OCR0A загрузим  значение 99, то получим 10 кГц: 8000000/8/100=10000

Предупреждаю сразу - я таймер с такими настройками еще не гонял. Предоставляю эту честь вам.

Еще одно замечание - использование этого режима (7) приводит к сужению диапазона изменения PWM-фактора: если в третьем режиме он может принимать значения 0-255, то в вышеприведенных примерах - 0-124 и 0-99 соответственно. Я полагаю, это не слишком тяжелая потеря?

whoim
Offline
Зарегистрирован: 03.11.2011

 >открыть даташит
Когда я приучусь это делать первым делом? ))))

>ATtiny13
Ну.. пока АтТини45 - в тринадцатую не влазит пока программа, все время не найду разобраться с множеством инфы о PINB

>в регистр OCR0A загружено значение 124
Я думал значение этого регистра - скважность..

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

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

>в регистр OCR0A загружено значение 124
Я думал значение этого регистра - скважность..

Ну остаьте же мне право на ошибку!!! ;)

Как я уже упоминал, седьмым режимом еще не баловался, а скакание по нескольким страницам даташита, на которых разбросаны части полезной информации, необходимой для правильного запуска конкретного режима - это как за стадом коров идти. Чуть зазевался, и готово - взрыв.

whoim
Offline
Зарегистрирован: 03.11.2011

 опть))))

В принципе, задача моя - получить частоту, на которой лампочка не будет "петь", а то очень странно получается - фары вибрируют ;)

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

step962
Offline
Зарегистрирован: 23.05.2011

 Таблица 11-9 (стр. 73) даташита на ATtiny13 (в принципе все тиньки имеют 0-й таймер с примерно одинаковой структурой, так что, наверное, и для 45-ки будет то же самое).

Кстати, есть режим 2 - ШИМ с фазовой коррекцией. Если не вдаваться в подробности, его основное отличие от быстрого ШИМА - вдвое меньшая частота на выходе при тех же самых остальных настройках. То есть с его помощью 8 кГц тоже не получить, но вот 16 - пожалуйста (при предделителе, настроенном на 1).

 

 

whoim
Offline
Зарегистрирован: 03.11.2011

 Для начала попробую 4кгц. Итак, что мне стало ясно.

1) Нам нужен Fast PWM
2) Нам нужен предделитель 8
3) Скважность должна изменяться 0..255

Итак, FAST PWM включается 

The fast Pulse Width Modulation or fast PWM mode (WGM0[2:0] = 3 or 7) provides a high frequency
PWM waveform generation option. The fast PWM differs from the other PWM option by
its single-slope operation. The counter counts from BOTTOM to TOP then restarts from BOTTOM.
TOP is defined as 0xFF when WGM0[2:0] = 3, and OCR0A when WGM0[2:0] = 7.

То есть надо установить в 3 или 7 регистры WGM0, WGM1, WGM2. Первые два находятся в регистре TCCR0A (0,1), последний в TCCR0B (3). 

Так в 3 или 7? И что значит - "установить в 3", например?

Ответ явно есть тут: The counter counts from BOTTOM to TOP then restarts from BOTTOM.
TOP is defined as 0xFF when WGM0[2:0] = 3, and OCR0A when WGM0[2:0] = 7.
Но пока непонятен толком. Ладно, пропустим, воспользуемся ранее приведенным примером и начнем так:

TCCR0A = B00000011; //включили FAST PWM
TCCR0B пока не трогаем - нужый нам бит в нуле.

Теперь - предделитель. Нам нужен 8. Согласно таблице:

и

Timer/Counter0 can be clocked directly by the system clock (by setting the CS0[2:0] = 1). This
provides the fastest operation, with a maximum timer/counter clock frequency equal to system
clock frequency (fCLK_I/O). Alternatively, one of four taps from the prescaler can be used as a
clock source. The prescaled clock has a frequency of either fCLK_I/O/8, fCLK_I/O/64, fCLK_I/O/256, or
fCLK_I/O/1024.

и

ставим так: TCCR0B = B00000010

---

ae[,kz ) правильно пока что?)

whoim
Offline
Зарегистрирован: 03.11.2011

 Также нам надо включить "выход" - на ноги? биты COM0A1 COM0A0

TCCR0A = B11000011;

The COM0A[1:0] and COM0B[1:0] bits control the behaviour of Output Compare pins OC0A and
OC0B, respectively. If any of the COM0A[1:0] bits are set, the OC0A output overrides the normal
port functionality of the I/O pin it is connected to. Similarly, if any of the COM0B[1:0] bits are set,
the OC0B output overrides the normal port functionality of the I/O pin it is connected to.

Получается, чтобы включить обе нужные мне PWM ноги аттини

мне нужны только биты COMA[1..0]?

whoim
Offline
Зарегистрирован: 03.11.2011

 Похоже нет, чтобы включить пины PB1 и PB0 мне нужно заложить в регистр это: B11110011?

whoim
Offline
Зарегистрирован: 03.11.2011

Все таки нужно: 11110011; ибо

COM0A [1:0] и COM0B [1:0] биты управляют поведением выхода компаратора контакты и OC0A
OC0B соответственно. Если любой из COM0A [1:0] бит установлен, выход OC0A заменяет обычное
Порт функциональности ввода / вывода он подключен. Аналогично, если любой из COM0B [1:0] биты,

 

whoim
Offline
Зарегистрирован: 03.11.2011

 Разрешение прерывания:

   cli         ; Запретить прерывания
   sei         ; Разрешить прерывания

Осталось разобраться в этом:

 

// отслеживаем прерывания по сравнению для канала A (OCIE2A) и по переполнению (TOIE2)
27
  TIMSK2 |= (1<<OCIE2A)+(1<<TOIE2);

И вспомнить, что в приведенном выше примере ШИМирования ноги 13 таймер у нас использовался только для вызова процедур, в которых ногами управляли "вручную". Что мне еще непонятно? назначение COM0A[1:0] and COM0B[1:0]

прекращаю - в голове бардак.. завтра выходной, после отсыпона почитаю еще даташит))))

whoim
Offline
Зарегистрирован: 03.11.2011

 Смешались в кучу кони, люди.. Комментирование блока

ISR(TIMER2_COMPA_vect) {
  PORTB = PINB & 0b11011111;
}
ISR(TIMER2_OVF_vect) {
  PORTB = PINB | 0b00100000;
}

не привело в отключению ШИМа на ногах вышеуказанных) Правда - тинька регулярно виснет, переставая реагировать на свои сигнальные ноги. Резет все возвращает в норму. Может - помирает вже от экспериментов..

step962
Offline
Зарегистрирован: 23.05.2011

 Пример инициализации для ATtiny:

 //********** PWM Config *********  
   
 TCCR0A |= ( ( 1 << COM0A1 ) | ( 1 << WGM01 ) | ( 1 << WGM00 ) ); // non inverting fast pwm  
 TCCR0B |= ( 1 << CS00 ); // start the timer with Prescaler = 1

Установка бита COM0A1 (при сброшенном COM0A0) активизирует пин OC0A (выход ШИМ-импульсов для канала A) в режиме "Clear OC0A on Compare Match" - низкий уровень на выходе будет присутствовать в период времени между значением, записанным в регистр OCR0A, и 255. И чем больше записанное в OCR0A значение, тем больше энергии получает внешнее устройство. А не наоборот, как в случае "11" (Для настройки канала B необходимо оперировать битами COM0B1 и COM0B0)

Установка битов WGM01 и WGM00 переводит оба (всегда оба - и A, и B) канала таймера/счетчика в режим работы "Fast PWM".

Установка бита CS00 (при сброшенных CS02, CS01) настраивает предделитель на работу без предделения ("clkI/O/(No prescaling)").

Опять-таки - для обоих каналов.

Все. Инструкция

DDRB |= 0x01;

конфигурирует нужный нам пин для вывода.

на всякий случай укажем

sei();

Должно заработать.

В TIMSK0 никаких битов устанавливать не надо - установленный в этом регистре бит естественным образом требует наличия процедуры обработки соответствующего прерывания. Это необходимо, если мы ШИМ "внутри производим и внутри же потребляем". Если же мы добиваемся чисто аппаратного управления внешним устройством без влияния на этот процесс АЛУ (пресловутая многопоточность), то - руки прочь от TIMSK0.

 

Еще.

Чтобы побыстрее запомнить какие биты чем рулят, следует помнить используемое соглашение о принятых означениях:

YYYxN - комбинация битов YYY оперирует настройками/данными канала x  в таймере/счетчике N.

Поэтому все комбинации вида YYYN настраивают оба канала.

Все комбинации, в которых N не равен нулю, относятся к любым другим таймерам/счетчикам, но только не к нулевому (он же единственный в ATtiny13, а может быть и в 45 - не смотрел).

step962
Offline
Зарегистрирован: 23.05.2011

whoim пишет:

 Также нам надо включить "выход" - на ноги? биты COM0A1 COM0A0

TCCR0A = B11000011;

The COM0A[1:0] and COM0B[1:0] bits control the behaviour of Output Compare pins OC0A and
OC0B, respectively. If any of the COM0A[1:0] bits are set, the OC0A output overrides the normal
port functionality of the I/O pin it is connected to. Similarly, if any of the COM0B[1:0] bits are set,
the OC0B output overrides the normal port functionality of the I/O pin it is connected to.

Получается, чтобы включить обе нужные мне PWM ноги аттини

мне нужны только биты COMA[1..0]?

А это, похоже, таки отличие 45-й тиньки от 13-й. В ней два таймера? Видимо, все же придется подгрузить даташит и на этот камень.