Нужно настроить ШИМ на 30КГц для dc-dc преобразователя на 180 вольт. Не получается его раскачать до нужной частоты. На arduin'е работал такой код: Код (C++): TCCR1B = TCCR1B & 0b11111000 | 0x01; analogWrite(10, 130); Набросал такой код: Код (C++): DDRB = 0x02; TCCR1A = (1<<COM1A1)|(1<<WGM10)|(1<<WGM12); TCCR1B = (1<<CS10); OCR1A = 128; Частота не та получается, в чем может быть проблема?
30КГц стандартным ШИМом не получится 8,8 потом сразу 65. Вот тут подробнее. Нужно запускать свой таймер на прерывание. Предделитель 1, OCRx = 0x0214 при 16,МГц
Работает на внешнем 16 МГц, если под "источником времени" вы подразумеваете источник тактирования, то это частота мк
Будет работать на меге8, регистр tccrb на atmega8 и atmega328 вроде бы не совпадают?(Попробовал как написано, не запустилось)
Чтобы из 16MHz получить 30kHz нужно делить на 533. Думаю, можно использовать (1<<WGM10)|(1<<WGM11) это 16000kHz / 512 = 31.25 kHz получается
Но мне не понятно, зачем COM1A1 - Clear OC1A/OC1B on Compare Match (Set output to low level) Это же не генерация частоты, а просто отключение пина через время. COM1A0 - Toggle OC1A/OC1B on Compare Match и OCR1A = 256; чтобы 50% скважность была.
Я написал что нужно для точного 30КГц, делитель и OCR от МК не зависит. Останется лишь добавить функцию с инверсией ножки в одну команду.
Не проверял, попробуйте сами: Код (C++): void setup() { cli(); TCCR1A = 0x00; // настройка таймера 1, канала А TCCR1B = 0x01; // предделитель CLK/1; OCR1A = 0x0214; // прерывание раз в 33мкс, если нужен полупериод то делим на два TIMSK = 0b00010000; // запуск таймера по совпадению 1А sei(); // разрешаем прерывания (запрещаем: cli(); ) } void loop() { } ISR(TIMER1_COMPA_vect) //обработчик прерывания по совпадению А { // тут инвертируем ногу TCNT1 = 0; //обнуляем регистр TCNT1 (мб не обязательно в данном случае) }
По формуле WGM 14 = Fast PWM mode : fOC1APWM = fclk_I/O / ( N * (1 + TOP)) N = 1 - prescaler TOP = ICR1 = 532. Скважность в регистре OCR1A.
Тестировал на Arduino LEONARDO. На осциллографе примерно 30 кГц получается. Код (C++): // Pins #define OC1A 9 #ifdef PRR0 #define TIMER1_PRTIM1 PRR0 #else #define TIMER1_PRTIM1 PRR #endif class Timer1 { public: enum CS : uint8_t { // Clock Select CS_STOP = 0, // No clock source. (Timer/Counter stopped), Initial CS_1 = _BV(CS10), // clkI/O/1 (No prescaling) CS_8 = _BV(CS11), // clkI/O/8 (From prescaler) CS_64 = _BV(CS11)|_BV(CS10), // clkI/O/64 (From prescaler) CS_256 = _BV(CS12), // clkI/O/256 (From prescaler) CS_1024 = _BV(CS12) |_BV(CS10), // clkI/O/1024 (From prescaler) CS_FALL = _BV(CS12)|_BV(CS11), // External clock source on T1 pin. Clock on falling edge (PD6 (T1/OC4D/ADC9)) CS_RISE = _BV(CS12)|_BV(CS11)|_BV(CS10) // External clock source on T1 pin. Clock on rising edge (PD6 (T1/OC4D/ADC9)) }; enum _WGM : uint8_t { // WGM internal bit mask _WGM__ = 0b0000, _WGM13 = 0b1000, _WGM12 = 0b0100, _WGM11 = 0b0010, _WGM10 = 0b0001, }; enum WGM : uint8_t { // Waveform Generation Mode WGM_0 = _WGM__, // Normal, Initial WGM_1 = _WGM10, // PWM, Phase Correct, 8-bit WGM_2 = _WGM11, // PWM, Phase Correct, 9-bit WGM_3 = _WGM11 | _WGM10, // PWM, Phase Correct, 10-bit WGM_4 = _WGM12, // CTC, Clear Timer on Compare Match OCR1A WGM_5 = _WGM12 | _WGM10, // Fast PWM, 8-bit, TOP=0xff WGM_6 = _WGM12 | _WGM11, // Fast PWM, 9-bit, TOP=0x1ff WGM_7 = _WGM12 | _WGM11 | _WGM10, // Fast PWM, 10-bit, TOP=0x3ff WGM_8 = _WGM13, // PWM, Phase and Frequency Correct, input capture ( IC ) function is disabled WGM_9 = _WGM13 | _WGM10, // PWM, Phase and Frequency Correct WGM_10 = _WGM13 | _WGM11, // PWM, Phase Correct, input capture ( IC ) function is disabled WGM_11 = _WGM13 | _WGM11 | _WGM10, // PWM, Phase Correct WGM_12 = _WGM13 | _WGM12, // CTC, Clear Timer on Compare Match, ICR1, input capture ( IC ) function is disabled WGM_14 = _WGM13 | _WGM12 | _WGM11, // Fast PWM, input capture ( IC ) function is disabled, TOP=ICR1 WGM_15 = _WGM13 | _WGM12 | _WGM11 | _WGM10, // Fast PWM, TOP=OCR1A }; static inline Timer1& instance() { static Timer1 i; return i; } void inline start_timer() { TIMER1_PRTIM1 &= ~(_BV(PRTIM1)); } // Initial void inline stop_timer() { TIMER1_PRTIM1 |= _BV(PRTIM1); } // Shuts down the Timer/Counter1 module void set_CS(Timer1::CS mode); // Clock Select void set_WGM(Timer1::WGM mode); // Waveform Generation Mode protected: private: Timer1(); ~Timer1(); Timer1(Timer1 const&) = delete; Timer1& operator= (Timer1 const&) = delete; }; Timer1::Timer1() { }; Timer1::~Timer1(){ }; void Timer1::set_CS( Timer1::CS mode ){ TCCR1B = ( TCCR1B & ~( _BV(CS12)|_BV(CS11)|_BV(CS10) ) ) | mode; } void Timer1::set_WGM( Timer1::WGM mode ){ TCCR1A = TCCR1A & ~( _BV(WGM11)|_BV(WGM10) ) | (_WGM11 & mode ? _BV(WGM11) : 0) | (_WGM10 & mode ? _BV(WGM10) : 0) ; TCCR1B = TCCR1B & ~( _BV(WGM13)|_BV(WGM12) ) | (_WGM13 & mode ? _BV(WGM13) : 0) | (_WGM12 & mode ? _BV(WGM12) : 0) ; } Timer1& tr1( Timer1::instance() ); void setup() { // put your setup code here, to run once: pinMode(OC1A, OUTPUT); // Пин 9 аппаратно связан с таймером 1. tr1.set_WGM(Timer1::WGM_14); // Fast PWM, TOP = ICR1. tr1.set_CS(Timer1::CS_1); // Делитель частоты = 1. TCCR1A = TCCR1A & ~( _BV(COM1A1)|_BV(COM1A0) ) | _BV(COM1A1); // Режим пина OC1A "non-inverted PWM" ICR1 = 532; // Частота 16000000 / CS_1 / (1 + ICR1) = 30018 Hz OCR1A = ICR1 / 5; // Скважность tr1.start_timer(); // Запускаем модуль Timer/Counter 1. } void loop() { // if ( ! --OCR1A ) OCR1A = ICR1; // Циклически меняем скважность delay(10); }
Извращение - не пользоваться функциями МК специально для того предназначенными. А ШИМ на прерываниях, это грубо из-за джиттера. Автора может быть WGM_6 устроит на частоте 31кГц. Зато все ШИМ выходы таймера можно будет использовать.