Управляем ШИМ. Пишем код коротко.

Тема в разделе "Микроконтроллеры AVR", создана пользователем ИгорьК, 20 мар 2014.

  1. ИгорьК

    ИгорьК Гуру

    Atmega328, она же Arduino UNO и т.п. имеет шесть каналов PWM.
    Предположим, стоит задача все их одновременно плавно заполнить на 100%.
    В случае с Ардуино это решается приблизительно так:
    Код (C):

    byte pins[6] = {3,5,6,9,10,11};   // Перечисляем ноги, которые работают как PWM;
    for (int i = 0; i <= 255; i++) {
        for (int a=0; a<6; a++) {
            analogWrite(pins[a], i);
            delay...;
        }
    }
    В случае с микроконтроллером, мы конфигурируем таймеры и решаем эту задачу так:
    Код (C):
    for (int i = 0; i <= 255; i++) {
        OCR0A=i;   // Пишем прямо в регистры;
        OCR0B=i;
        OCR1AL=i;
        OCR1BL=i;
        OCR2A=i;
        OCR2B=i;
        delay...;
    }
    Вопрос вот в чем. Как через дефайны или еще как-то скомпоновать регистры OCR0A, OCR0B и т.д. для получения записи как в Ардуино? Если в случае с 238 мегой такая запись еще проходит, то с 15 PWM в 2560 - это перебор. И, тем более, если с этими ногами нужно сделать что-то более продвинутое, чем просто зажечь одновременно.
     
    Последнее редактирование: 20 мар 2014
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    Запись в регистр - это просто запись в некоторую ячейку памяти (это называется "отображение регистров в память").

    В файле \arduino-1.0.5\hardware\tools\avr\avr\include\avr\iom328p.h ищем определение регистра:

    #define OCR0A _SFR_IO8(0x27)

    _SFR_IO8 определен так:

    #define __SFR_OFFSET 0x20
    #define _SFR_IO8(io_addr) ((io_addr) + __SFR_OFFSET)

    Так что можно сделать массив регистров и писать в него в цикле.
    Могут быть тонкости с приведением к нужному типу, но общий смысл не меняется.
     
    ИгорьК нравится это.
  3. ИгорьК

    ИгорьК Гуру

    Буду разбираться.
     
  4. ИгорьК

    ИгорьК Гуру

    Итак, решение задачи для Atmega2560 - она же Ардуино Мега.
    Код (C):
    // В определениях настраиваем все таймеры на режим 8 бит;
    // Перечисляем в массив адреса всех регистров сравнения таймеров,
    // да еще в порядке расположения ног Ардуино Мега: 2-13, 44-46;
    int pinsForPWM [] = {0x9A, 0x9C, 0x48, 0x98, 0xA8, 0xAA, 0xAC, 0xB4, 0xB2, 0x88, 0x8A, 0x27, 0x12C, 0x12A, 0x128};
    int *pPinsForPWM; // указатель типа int;
    int a, i;

    // В теле программы;

    for (i = 0; i <= 255; i++) {
                for (a=0; a<15; a++) {
                    pPinsForPWM = (int *) pinsForPWM[a]; // Присваиваем указателю адреса регистров;
                    *pPinsForPWM = i; // Пишем в регистры число для заполнения PWM;
                    delay_ms(10);
                }
    }
     
     
    Последнее редактирование: 25 мар 2014
    acos и Megakoteyka нравится это.
  5. Megakoteyka

    Megakoteyka Оракул Модератор

    int *pPinsForPWM; ---> int *pPinForPWM; это же один регистр :)
    Пришел, увидел, победил. Респект!
     
  6. ИгорьК

    ИгорьК Гуру

    Ну да, можно еще упаковать:
    Код (C):
    pPinsForPWM = (int *) pinsForPWM[a];
    *pPinsForPWM = i;
    // равно одной строке:
    *(int *) pinsForPWM[a] = i;
    /******************************************************************/
    // Итого:
    for(i=0; i<=255; i++){
          for(a=0; a<15; a++){
                  *(int *) pinsForPWM[a] = i; // Преобразуем в адрес содержание массива
                                              // и пишем по адресу значение i;  
                  delay_ms(10);
          }
    }
     
    Последнее редактирование: 26 мар 2014
    Airbus и Megakoteyka нравится это.
  7. TiPash235j

    TiPash235j Нерд

    Добрый время суток. Интересует как можно, а точней как будет выглядеть код, что бы изменить чистоту ШИМа. А ещо возможно ли, на ардуинке задать работу ШИМ. На 1 выходе первый полупериод + 5 вольт, а на другом выходе во втором половине полупериода + 5 вольт. Два выхода но работают по очереди. Посмотрел статейку https://arduino-info.wikispaces.com/Arduino-PWM-Frequency но неврозумило як це работает)))). Зорание большое спасибо.
     
  8. TiPash235j

    TiPash235j Нерд

    Вот что-то подобное IMG_0565.JPG
     
  9. Airbus

    Airbus Радиохулиган Модератор

    А ещё прикольный ШИМ можно соорудить из USART если через TX всё время передавать цифру.Нолю будет соответствовать 00000000 (то есть 0%)а 255 11111111(100% соответственно) всем остальным цифрам промежуточное значение.Бодрейт можно выставить любой на результат не влияет а так всё отлично работает.Идею подсмотрел у Di Halt http://tinyurl.com/z8ac5zu
     
  10. ИгорьК

    ИгорьК Гуру

    Посмотрите здесь.
     
  11. Onkel

    Onkel Гуру

    если бы старт/стоп битов не было бы, все бы так и было бы.
     
    Airbus нравится это.
  12. Airbus

    Airbus Радиохулиган Модератор

    Ну да так и есть хотя на глаз и не заметно.Просто ноля в чистом виде не будет
     
  13. Onkel

    Onkel Гуру

    на глаз шим 1/255 на светодиодах заметен. Глаз ведь имеет логарифмический характер чувствительности.