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 - это перебор. И, тем более, если с этими ногами нужно сделать что-то более продвинутое, чем просто зажечь одновременно.
Запись в регистр - это просто запись в некоторую ячейку памяти (это называется "отображение регистров в память"). В файле \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) Так что можно сделать массив регистров и писать в него в цикле. Могут быть тонкости с приведением к нужному типу, но общий смысл не меняется.
Итак, решение задачи для 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); } }
Ну да, можно еще упаковать: Код (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); } }
Добрый время суток. Интересует как можно, а точней как будет выглядеть код, что бы изменить чистоту ШИМа. А ещо возможно ли, на ардуинке задать работу ШИМ. На 1 выходе первый полупериод + 5 вольт, а на другом выходе во втором половине полупериода + 5 вольт. Два выхода но работают по очереди. Посмотрел статейку https://arduino-info.wikispaces.com/Arduino-PWM-Frequency но неврозумило як це работает)))). Зорание большое спасибо.
А ещё прикольный ШИМ можно соорудить из USART если через TX всё время передавать цифру.Нолю будет соответствовать 00000000 (то есть 0%)а 255 11111111(100% соответственно) всем остальным цифрам промежуточное значение.Бодрейт можно выставить любой на результат не влияет а так всё отлично работает.Идею подсмотрел у Di Halt http://tinyurl.com/z8ac5zu