- Форум
- Наши простые устройства
- Программирование
- Разработка программной ШИМ для управления двумя ДПТ на основе статьи "Нисходящее программирование"
Разработка программной ШИМ для управления двумя ДПТ на основе статьи "Нисходящее программирование"
- ARV
- Не в сети
- Администратор
Не углубляйтесь в дебри.
я не ленивый, я энергосберегающий...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
Вы торопите события.)ARV пишет: <...>Для операции определения положения бита в байте по его номеру в avr-gcc даже специальный макрос предусмотрен, _BV(x) - от слов Bit Value.
<...>#define _BV(x) (1 << (x))
Если вам нравится работать с "инверсными" битами, то ранее указанная вами запись будет выглядеть так:Нет лишних, загромождающих поле зрения единичек, и сразу понятно, о каком именно бите идет речь. Да и в случае чего изменить проще, если номера пинов захочется поменять.#define BTN_1_UP ~_BV(0) #define BTN_1_DWN ~_BV(1) и т.д.
Я пытаюсь осознать "указатели", а вы уже новую вводную даёте.
Всё-таки, я попробую сначала без специальных макросов...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
Соберусь с мыслями - попробую обосновать.)
/*
* ARV_PWM.c
*/
// 0b11010010 = 255-45 = 0b00101101 = 255-210 =
#include <avr/io.h>
#define F_CPU 8000000UL
#define BTN_UP_0 (0b11111110) //нажата кнопка "+" нулевого канала
#define BTN_DWN_0 (0b11111101) //нажата кнопка "-" нулевого канала
#define BTN_UP_1 (0b11111011) //нажата кнопка "+" первого канала
#define BTN_DWN_1 (0b11110111) //нажата кнопка "-" первого канала
#define ENABLE (PINB == 0b11111111) //все кнопки отпущены
#define STEP_UP (1)
#define STEP_DWN (-1)
#define WIDTH_PWM_MAX 44
#define WIDTH_PWM_MIN 0
void change_width_pwm(register unsigned char *_pwm, const char a)
{
int pwm = *_pwm;
if(a == 1)
{
if(pwm < WIDTH_PWM_MAX){*_pwm = *_pwm + a;}
else{*_pwm = WIDTH_PWM_MIN;}
}
if(a != 1)
{
if(pwm > WIDTH_PWM_MIN){*_pwm = *_pwm + a;}
else{*_pwm = WIDTH_PWM_MAX;}
}
}
int main()
{
DDRD = 0xFF;
PORTD = 0xFF;
DDRB = 0x00;
PORTB = 0xFF;
register unsigned char port_B_state = 0;
register unsigned char port_D_state;
unsigned char enable_change_pwm = 1; //разрешение изменения pwm
register unsigned char counter_pwm = 0; //счётчик ширины pwm
register unsigned char counter_button = 0; //счётчик подтверждения состояния кнопок
unsigned char width_pwm_0 = 0; //индекс ширины pwm_0
unsigned char width_pwm_1 = 0; //индекс ширины pwm_1
const int width_pwm[45] = { //массив с набором ширин импульса
0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,18,19,21,24,26,28,31,34,38,42,46,50,55,61,67,74,81,89,98,108,119,131,144,158,174,192,211,232,255};
while(1)
{
if(counter_pwm >= width_pwm[width_pwm_0]){port_D_state &= ~(1 << PORTD0);} //готовимся погасить pwm_0
if(counter_pwm >= width_pwm[width_pwm_1]){port_D_state &= ~(1 << PORTD1);} //готовимся погасить pwm_1
PORTD = port_D_state; //устанавливаем pwm_0 и pwm_1
counter_pwm ++; // увеличиваем счётчик ширины pwm
if(counter_pwm == 0b00000000) //каждый период pwm
{
port_D_state = ((1 << PORTD0) | (1 << PORTD1)); //включаем
port_B_state = PINB; //запоминаем состояние кнопок
counter_button ++;
}
if(counter_button & 0b11111000) //проверяем состояние кнопок через Х периодов
{
counter_button = 0;
if(port_B_state == PINB) //если состояние кнопок совпадает после Х периодов
{
if(enable_change_pwm) //разрешаем изменение pwm
{
enable_change_pwm = 0;
switch(port_B_state)
{
case BTN_UP_0 : change_width_pwm(&width_pwm_0, STEP_UP);
break;
case BTN_DWN_0 : change_width_pwm(&width_pwm_0, STEP_DWN);
break;
case BTN_UP_1 : change_width_pwm(&width_pwm_1, STEP_UP);
break;
case BTN_DWN_1 : change_width_pwm(&width_pwm_1, STEP_DWN);
break;
}
}
}
}
if(ENABLE){enable_change_pwm = 1;}
}
}
Нет, лучше так:
void change_width_pwm(register unsigned char *_pwm, const int a)
{
int pwm = *_pwm;
switch(a)
{
case STEP_UP :
if(pwm < WIDTH_PWM_MAX){*_pwm = *_pwm + a;}
else{*_pwm = WIDTH_PWM_MIN;}
break;
case STEP_DWN :
if(pwm > WIDTH_PWM_MIN){*_pwm = *_pwm + a;}
else{*_pwm = WIDTH_PWM_MAX;}
break;
}
}
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
Для одних и тех же состояний - разные дефайны навыдумывал.
Эх...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- ARV
- Не в сети
- Администратор
я не ленивый, я энергосберегающий...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
У меня всё это время ушло, на осознание указателя и с чем его едят.
И то - до конца не осознал.
Подождите ещё не много - всё-таки сам хочу дойти.)
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- ARV
- Не в сети
- Администратор
я не ленивый, я энергосберегающий...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
Когда пытаюсь сформулировать мысль, в голове сразу возникают куски кода, и пошло-поехало - if на if налезает и while'ом погоняет...)
Сейчас с работой завал.
Маловато времени...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
ARV пишет: Мда...
Такой удручающий результат - это от того, что мысли - "скакуны".)
Если не использовать "прискакавший" в голову массив, то функция для разных кейсов упрощается до неприличной
#define F_CPU 8000000UL
#define BTN_UP_0 (0b11111110) //нажата кнопка "+" нулевого канала
#define BTN_DWN_0 (0b11111101) //нажата кнопка "-" нулевого канала
#define BTN_UP_1 (0b11111011) //нажата кнопка "+" первого канала
#define BTN_DWN_1 (0b11110111) //нажата кнопка "-" первого канала
#define ENABLE (PINB == 0b11111111) //все кнопки отпущены
#define UP (10)
#define DWN (-10)
void change_width_pwm(unsigned char *b, const int a)
{
*b +=a;
}
register unsigned char Button_state = 0;
register unsigned char counter_Button = 0; //счётчик состояния кнопок
unsigned char width_Pwm_0 = 0; //ширинa pwm_0
unsigned char width_Pwm_1 = 0; //ширинa pwm_1
register unsigned char counter_Pwm = 0; //счётчик ширины pwm
unsigned char enable_change_Pwm = 1;
switch(Button_state){
case BTN_UP_0 : change_width_pwm(&width_Pwm_0, UP);
break;
case BTN_DWN_0 : change_width_pwm(&width_Pwm_0, DWN);
break;
case BTN_UP_1 : change_width_pwm(&width_Pwm_1, UP);
break;
case BTN_DWN_1 : change_width_pwm(&width_Pwm_1, DWN);
break;
}
Так лучше, если конечно я объясню это используя принципы нисходящего программирования?..
Дефолт ещё не использован, но - думаю. Крепко.)
P.S. Одно не могу понять - почему это работает.)))
Точнее - почему оно "по кругу гоняет" ширину импульса...
Не, понял - тоже самое "переполнение" width_Pwm!!!
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- ARV
- Не в сети
- Администратор
По кругу - это см. в функцию change_width_pwm - там следует контролировать границы изменения.
Подход, когда работающий код объясняется какими-то принципами, уже не имеет смысла. Принцип играет роль, когда он помогает достичь результата, а если результат достигнут "беспринципными" методами, то, как говорится, победителей не судят
я не ленивый, я энергосберегающий...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
ARV пишет: Работает - это хорошо.
По кругу - это см. в функцию change_width_pwm - там следует контролировать границы изменения.
<...>
В принципе - конечно надо, но в данном случае - мне как раз очень подходит "по кругу".
Это удобно - вблизи верхней или нижней границы изменения не гнать через весь диапазон соответствующей кнопкой, а за пару шагов - "... и всё опять начать с нуля...".
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
/*
* ARV_PWM_array_ind.c
*
* Created: 22.03.2017 17:27:48
* Author : Настя
*/
#include <avr/io.h>
#define F_CPU 8000000UL
#define _0 (0b00111111)
#define _1 (0b00000110)
#define _2 (0b01011011)
#define _3 (0b01001111)
#define _4 (0b01100110)
#define _5 (0b01101101)
#define _6 (0b01111101)
#define _7 (0b00000111)
#define _8 (0b01111111)
#define _9 (0b01101111)
#define BTN_UP_0 (0b11111110) /*нажата кнопка "+" нулевого канала*/
#define BTN_DWN_0 (0b11111101) /*нажата кнопка "-" нулевого канала*/
#define BTN_UP_1 (0b11111011) /*нажата кнопка "+" первого канала*/
#define BTN_DWN_1 (0b11110111) /*нажата кнопка "-" первого канала*/
#define BTN_UP_2 (0b11101111) /*нажата кнопка "+" второго канала*/
#define BTN_DWN_2 (0b11011111) /*нажата кнопка "-" второго канала*/
#define ENABLE (PINB == 0b11111111) /*все кнопки отпущены*/
#define CHECK_BTN (0b11110000) /*количество периодов проверки */
#define NEXT (1)
#define PREV (-1)
#define WIDTH_PWM_MAX (44)
#define WIDTH_PWM_MIN (0)
#define NUMBER_IND (0b00000110) /* общее число разрядов индикации - число каналов Pwm * 2 */
#define IND_TENS_PWM_0 (0b00000001)
#define IND_ONES_PWM_0 (0b00000010)
#define IND_TENS_PWM_1 (0b00000100)
#define IND_ONES_PWM_1 (0b00001000)
#define IND_TENS_PWM_2 (0b00010000)
#define IND_ONES_PWM_2 (0b00100000)
//массив ширин Pwm (округлённая геометрическая прогрессия со знаменателем ~1.1)
unsigned char width_Pwm[45] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,15,16,18,19,21,24,26,28,31,34,38,42,46,50,55,61,67,74,81,89,98,108,119,131,144,158,174,192,211,232,255
};
void change_width_Pwm(unsigned char *b, const int a, const char c, const char d)
{
if((c - *b) == 0) // переход через минимум или максимум ширины
{
*b = d;
}
else *b += a;
}
//массив единиц индикации
unsigned char ind_width_ones_Pwm[46] = {
_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_0,_1,_2,_3,_4,_0
};
//массив десятков индикации
unsigned char ind_width_tens_Pwm[45] = {
_0,_0,_0,_0,_0,_0,_0,_0,_0,_0,_1,_1,_1,_1,_1,_1,_1,_1,_1,_1,_2,_2,_2,_2,_2,_2,_2,_2,_2,_2,_3,_3,_3,_3,_3,_3,_3,_3,_3,_3,_4,_4,_4,_4,_4
};
//изменение индикации
void change_ind_Pwm(unsigned char *tens, unsigned char *ones, unsigned char i_width_Pwm)
{
*ones = i_width_Pwm; //индикация равна индексу ширины pwm
*tens = i_width_Pwm;
}
//индикация
void ind_Pwm(unsigned char ind_width_Pwm[], unsigned char *ind)
{
PORTA = ~ind_width_Pwm[*ind];
}
int main()
{
DDRA = 0xFF;
PORTA = 0x00;
DDRB = 0x00;
PORTB = 0xFF;
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0xFF;
PORTD = 0xFF;
register unsigned char state_Button = 0; //состояние кнопок
register unsigned char counter_Button = 0; //счётчик состояния кнопок
unsigned char ind_Ones_0 = 0; //индекс индикации десятков Pwm 0
unsigned char ind_Tens_0 = 0; //индекс индикации единиц Pwm 0
unsigned char ind_Ones_1 = 0;
unsigned char ind_Tens_1 = 0;
unsigned char ind_Ones_2 = 0;
unsigned char ind_Tens_2 = 0;
unsigned char width_Pwm_0 = 0; //индекс ширины Pwm 0
unsigned char width_Pwm_1 = 0;
unsigned char width_Pwm_2 = 0;
register unsigned char counter_Pwm = 0; //счётчик ширины pwm
register unsigned char counter_ind_Pwm = 0; //счётчик индикации
unsigned char enable_change_Pwm = 1; //разрешение изменения pwm
register unsigned char ind_state_Pwm = 0b00000010; // счётчик динамической индикации
while(1)
{
register unsigned char state_Pwm; //состояние Pwm
state_Pwm = ((1 << PORTD0) | (1 << PORTD1)| (1 << PORTD2)); //включаем
if(counter_Pwm >= width_Pwm[width_Pwm_0]) //проверяем
{
state_Pwm &= (~(1 << PORTD0)); //готовимся погасить pwm_1
}
if(counter_Pwm >= width_Pwm[width_Pwm_1])
{
state_Pwm &= (~(1 << PORTD1));
}
if(counter_Pwm >= width_Pwm[width_Pwm_2])
{
state_Pwm &= (~(1 << PORTD2));
}
PORTD = state_Pwm; //устанавливаем pwm_0, pwm_1 и pwm_2
counter_Pwm ++; //считаем ширину Pwm
if(counter_Pwm == 0) //каждый период pwm
{
//======================================динамическая индикация==================================
counter_ind_Pwm ++; //считаем индикацию
if(counter_ind_Pwm == NUMBER_IND)
{
counter_ind_Pwm = 0;
}
ind_state_Pwm = (1 << counter_ind_Pwm); //последовательно мигаем индикаторами
PORTC = ind_state_Pwm;
switch(ind_state_Pwm)
{
case IND_TENS_PWM_0 : ind_Pwm(ind_width_tens_Pwm, &ind_Tens_0);//выводим соответственно десятки
break;
case IND_ONES_PWM_0 : ind_Pwm(ind_width_ones_Pwm, &ind_Ones_0);//единицы
break;
case IND_TENS_PWM_1 : ind_Pwm(ind_width_tens_Pwm, &ind_Tens_1);
break;
case IND_ONES_PWM_1 : ind_Pwm(ind_width_ones_Pwm, &ind_Ones_1);
break;
case IND_TENS_PWM_2 : ind_Pwm(ind_width_tens_Pwm, &ind_Tens_2);
break;
case IND_ONES_PWM_2 : ind_Pwm(ind_width_ones_Pwm, &ind_Ones_2);
break;
}
//===============================================================================================
//==================================================антидребезг нажатия==========================
state_Button = PINB; //запоминаем состояние кнопок
counter_Button ++;
}
if(counter_Button & CHECK_BTN) //через CHECK_BTN периодов (антидребезг нажатия)
{
counter_Button = 0; //сбрасываем счётчик кнопок
if(state_Button == PINB) //если состояние кнопок совпадает
{
if(enable_change_Pwm) //если разрешено изменение
{
enable_change_Pwm = 0; //сбрасываем разрешение
//=========================================обработка кнопок=========================================
switch(state_Button)
{
case BTN_UP_0 : change_width_Pwm(&width_Pwm_0, NEXT, WIDTH_PWM_MAX, WIDTH_PWM_MIN);//увеличиваем ширину
change_ind_Pwm(&ind_Tens_0, &ind_Ones_0, width_Pwm_0); //увеличиваем индикацию
break;
case BTN_DWN_0 : change_width_Pwm(&width_Pwm_0, PREV, WIDTH_PWM_MIN, WIDTH_PWM_MAX);//уменьшаем ширину
change_ind_Pwm(&ind_Tens_0, &ind_Ones_0, width_Pwm_0); //уменьшаем индикацию
break;
case BTN_UP_1 : change_width_Pwm(&width_Pwm_1, NEXT, WIDTH_PWM_MAX, WIDTH_PWM_MIN);
change_ind_Pwm(&ind_Tens_1, &ind_Ones_1, width_Pwm_1);
break;
case BTN_DWN_1 : change_width_Pwm(&width_Pwm_1, PREV, WIDTH_PWM_MIN, WIDTH_PWM_MAX);
change_ind_Pwm(&ind_Tens_1, &ind_Ones_1, width_Pwm_1);
break;
case BTN_UP_2 : change_width_Pwm(&width_Pwm_2, NEXT, WIDTH_PWM_MAX, WIDTH_PWM_MIN);
change_ind_Pwm(&ind_Tens_2, &ind_Ones_2, width_Pwm_2);
break;
case BTN_DWN_2 : change_width_Pwm(&width_Pwm_2, PREV, WIDTH_PWM_MIN, WIDTH_PWM_MAX);
change_ind_Pwm(&ind_Tens_2, &ind_Ones_2, width_Pwm_2);
break;
}
//==================================================================================================
}
}
}
//========================================антидребезг отпускания====================================
state_Button = PINB; //запоминаем состояние кнопок
counter_Button ++;
if(counter_Button & CHECK_BTN) //через CHECK_BTN периодов
{
counter_Button = 0; //сбрасываем счётчик кнопок
if(ENABLE)
{
enable_change_Pwm = 1; //если кнопки не нажаты (отпущены после нажатия и обработки) разрешаем изменения ширины
}
}
}
}
Добавил третий канал шим и прикрутил индикацию на семисегментных индикаторах.))
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- ARV
- Не в сети
- Администратор
я не ленивый, я энергосберегающий...
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.
- plis
- Автор темы
- Не в сети
- Захожу иногда
- Сообщений: 47
- Спасибо получено: 0
Или имя компьютера, или имя пользователя.
А на самом деле - имя моей дочери.
Ноутбук её.
А Atmel файл сам подписывает.
А я не меняю.
))))))
Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.