Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.91/11: Рейтинг темы: голосов - 11, средняя оценка - 4.91
0 / 0 / 0
Регистрация: 01.03.2017
Сообщений: 27
1

Оптимизация для повышения частоты ШИМ

29.10.2020, 20:37. Показов 2257. Ответов 36

Author24 — интернет-сервис помощи студентам
Добрый день. Пишу программу для многоканального ШИМ-контроллера на основе Attiny13. Так как у него всего два аппаратных канала, использую программное управление в прерывании таймера.
Сначала планировалось ШИМить с низкой частотой (10 Гц), но шумовые эффекты все равно значительны. А вот с поднятием частоты до 20 кГц возникли затруднения.

Сначала было так (обработчик прерывания). Такой код выполнялся 54 такта и при тактовой 9.6 МГц и разрешении ШИМ 16 уровней давал менее 10 кГц на выходах.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Прерывание по совпадению счетчика
// Выходные каналы - PB0, PB1, PB2 и PB3
// Уставки ШИМ - pwm1...pwm4
ISR(TIM0_COMPA_vect)
{
    if(cnt<pwm1) PORTB |= (1<<0);
    else PORTB &= ~(1<<0);
    if(cnt<pwm2) PORTB |= (1<<1);
    else PORTB &= ~(1<<1);
    if(cnt<pwm3) PORTB |= (1<<2);
    else PORTB &= ~(1<<2);
    if(cnt<pwm4) PORTB |= (1<<3);
    else PORTB &= ~(1<<3);
    cnt++;
}
Пораскинул мозгами, перенёс этот код в главный цикл, формировать массив с 16 значениями на 16 моментов времени.
Обработчик уменьшился, теперь 30 тактов, однако оказалось, что из-за накладных расходов едва ли дотянулось до 10 кГц.
C
1
2
3
4
5
ISR(TIM0_COMPA_vect)
{
    PORTB = port_out_table[cnt];
    cnt == PWM_RES ? cnt = 0 : cnt++;
}
Глянул ассемблерный листинг, а там куча "лишних" операций, в основном освобождение необходимых регистров:
Кликните здесь для просмотра всего текста
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
00000019  PUSH R1       Push register on stack 
0000001A  PUSH R0       Push register on stack 
0000001B  IN R0,0x3F        In from I/O location 
0000001C  PUSH R0       Push register on stack 
0000001D  CLR R1        Clear Register 
--- C:\Users\Pa-vm-10\Documents\Atmel Studio\7.0\t13fan-control\t13fan-control\Debug/.././main.c 
0000001E  PUSH R24      Push register on stack 
0000001F  PUSH R30      Push register on stack 
00000020  PUSH R31      Push register on stack 
    PORTB = port_out_table[cnt];
00000021  LDS R30,0x0062        Load direct from data space 
00000023  LDI R31,0x00      Load immediate 
00000024  SUBI R30,0x7F     Subtract immediate 
00000025  SBCI R31,0xFF     Subtract immediate with carry 
00000026  LDD R24,Z+0       Load indirect with displacement 
00000027  OUT 0x18,R24      Out to I/O location 
    cnt == PWM_RES ? cnt = 0 : cnt++;
00000028  LDS R24,0x0062        Load direct from data space 
0000002A  CPI R24,0x0F      Compare with immediate 
0000002B  BRNE PC+0x04      Branch if not equal 
--- No source file -------------------------------------------------------------
0000002C  STS 0x0062,R1     Store direct to data space 
0000002E  RJMP PC+0x0004        Relative jump 
0000002F  SUBI R24,0xFF     Subtract immediate 
00000030  STS 0x0062,R24        Store direct to data space 
00000032  POP R31       Pop register from stack 
00000033  POP R30       Pop register from stack 
00000034  POP R24       Pop register from stack 
00000035  POP R0        Pop register from stack 
00000036  OUT 0x3F,R0       Out to I/O location 
00000037  POP R0        Pop register from stack 
00000038  POP R1        Pop register from stack 
00000039  RETI      Interrupt return


Я более-менее имею опыт в ассемблере, но переписывать весь код в нём не хочется, остальная часть проги (юарт, проверка настроек, контроль температур) написана и отлажена. Что можно сделать конкретно в этом обработчике, не представляю. Как-то перенести часть операций в медленную часть, что-ли.
Есть отчаянные варианты, например забить в OSCCAL максимальное значение, но тогда может пострадать чтение и запись еепром. Или внешний ТГ на 20 МГц, но ножек не хватит.
Переделать аппаратную часть, вроде фильтра на выход, это самое сложное решение, как обычно. Аппарат... немножко неразборный, и проще сделать новый с нуля.

Буду благодарен за любые намёки, наводки и прочее.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.10.2020, 20:37
Ответы с готовыми решениями:

регулирование частоты шим
сабж, помогите. не пойму как у atmega регулируется частота шим.

Реализация плавного повышения частоты пьезоизлучателя.
Добрый вечер. Неполучается написать программу на С для atmega8, которая бы при удержании кнопки...

Изменение частоты/скважности ШИМ
Здравствуйте, уважаемые участники форума. Возник момент: хочу регулировать частоту ШИМ на...

Измерение частоты и скважности ШИМ (Infineon XC2000)
Необходимо измерять частоту и скважность ШИМа в непрерывном режиме. Навскидку есть пара...

Программа для понижения/повышения частоты работы процессора?
Какая программа может стартуя вместе с виндовс автоматически понижать/повышать частоту работы...

36
4393 / 2243 / 252
Регистрация: 28.10.2011
Сообщений: 8,574
Записей в блоге: 6
29.10.2020, 21:43 2
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Пишу программу для многоканального ШИМ-контроллера на основе Attiny13.
Других контроллеров нет и нет возможности купить?
Почему не выбрать подходящий с нужным числом аппаратных каналов ШИМ?

Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Глянул ассемблерный листинг
Уровень оптимизации -O0?
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
29.10.2020, 21:43 3
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
if(cnt<pwm1) PORTB |= (1<<0);
здесь при кажущейся простоте происходит три фазы чтение-модификация-запись
попробуй с временной переменной
C
1
2
3
4
5
6
unsigned char tmp=0;
if(cnt<pwm1) tmp |= (1<<0);
if(cnt<pwm2) tmp |= (1<<1);
if(cnt<pwm3) tmp |= (1<<2);
if(cnt<pwm4)tmp |= (1<<3);
PORTB = tmp;
0
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
29.10.2020, 22:57 4
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Я более-менее имею опыт в ассемблере, но переписывать весь код в нём не хочется
Увы, придётся. Сесть одновременно на оба всем известных стула, при этом ещё и съев рыбку, не получится.
Конечно же не код всей программы, но именно это прерывание надо написать на асме целиком. Бывал в подобной ситуации уже.

Добавлено через 2 минуты
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Или внешний ТГ на 20 МГц, но ножек не хватит.
Для внешнего именно генератора (а не кварца) достаточно одной ножки.
0
Тутошний я
2146 / 1201 / 225
Регистрация: 03.11.2009
Сообщений: 4,416
Записей в блоге: 2
30.10.2020, 00:38 5
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
для многоканального ШИМ-контроллера
а это точно ШИМ? зачем эти строчки? зачем её постоянно сбрасывать?
C
1
else PORTB &= ~(1<<0);
по моему так лучше
C
1
2
3
4
5
6
7
8
ISR(TIM0_COMPA_vect)
{
    if(cnt=16){
       cnt = 0;
       PORTB = 0;
    }
    cnt++;
}
и в основном цикле
C
1
2
3
4
if(cnt<pwm1) PORTB |= (1<<0);
    if(cnt<pwm2) PORTB |= (1<<1);
    if(cnt<pwm3) PORTB |= (1<<2);
    if(cnt<pwm4) PORTB |= (1<<3);
примерно так.

Добавлено через 23 минуты
Цитата Сообщение от ValeryS Посмотреть сообщение
происходит три фазы чтение-модификация-запись
это же не stm. и я надеюсь они проводят к командам andi и ori, которые занимают 1 такт.
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
30.10.2020, 08:30 6
Цитата Сообщение от Grey Посмотреть сообщение
это же не stm. и я надеюсь они проводят к командам andi и ori, которые занимают 1 такт.
физика процесса от этого не изменяется такт может быть и один а фазы три
и потом я же ничего не утверждал, я сказал
Цитата Сообщение от ValeryS Посмотреть сообщение
попробуй
0
0 / 0 / 0
Регистрация: 01.03.2017
Сообщений: 27
30.10.2020, 10:50  [ТС] 7
Цитата Сообщение от locm Посмотреть сообщение
Других контроллеров нет и нет возможности купить?
Хорошее, но неудобное решение. Есть куча attiny13 и atmega8, но даже у меги нет четырех каналов. Из того, что есть, подходит только стм32, но для такой простой задачи морально неудобно её использовать. А еще, тини13 были как раз для этого и закуплены.
Цитата Сообщение от locm Посмотреть сообщение
Уровень оптимизации -O0?
Нет, но на любом уровне оптимизации генерируется такой код.
Цитата Сообщение от ValeryS Посмотреть сообщение
попробуй с временной переменной
Пробовал и так, экономит 5 тактов, но с массивом возможных значений все равно быстрее выходит.
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
именно это прерывание надо написать на асме целиком.
Так и думал. Пока не могу придумать, как избежать сохранения шести регистров в стек и извлечения их. Когда писал проги целиком на асме, просто не использовал в основной программе те регистры, которые задействованы в прерывании.
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
Для внешнего именно генератора (а не кварца) достаточно одной ножки.
Да там все ножки заняты. У него еще подключен термодатчик и вход юарта для записи настроек. Может, одним каналом пожертвую...
Цитата Сообщение от Grey Посмотреть сообщение
а это точно ШИМ? зачем эти строчки? зачем её постоянно сбрасывать?
Точно ШИМ, даже в железе работает)
Алгоритм был такой: если счетчик меньше уставки, то поднимаем единицу, а если больше, то опускаем. Проверяем это n раз за период ШИМ.
Цитата Сообщение от Grey Посмотреть сообщение
по моему так лучше
Боюсь, Ваш код будет работать, только если основной цикл выполняется достаточно часто. У меня же он имеет период на три порядка больше, чем прерывание. Там почти килобайт кода.


Спасибо всем, пока попробую написать прерывание на ассемблере. Если не выйдет, придется изготовить новый макет устройства, с фильтрами и мощными ключами. Тесты показали, что ШИМ на 10 Гц очень шумный, а вот немного сглаженый сигнал уже практически бесшумен. Нагрузка - обычные 3-pin вентиляторы. Делаю охлаждение для серверов, чьи материнские платы не умеют управлять кулерами, а заказывать цифровой контроллер это большое время и гораздо дороже своей разработки.
0
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
30.10.2020, 10:54 8
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Так и думал. Пока не могу придумать, как избежать сохранения шести регистров в стек и извлечения их. Когда писал проги целиком на асме, просто не использовал в основной программе те регистры, которые задействованы в прерывании.
Переходите на CVAVR, там есть строгие соглашения, какие регистры можно безболезненно тереть.
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
30.10.2020, 12:19 9
Цитата Сообщение от ValeryS Посмотреть сообщение
физика процесса от этого не изменяется такт может быть и один а фазы три
"физика" предусмотрена, в данном случае, в процессоре (команды
Assembler
1
cbr, sbr
). А в цифре можно не делать для этого "три фазы". Достаточно одной.

ТС,
1) используйте значение самогО таймера, для временнЫх тиков. То есть в Вашем коде cnt = TCNT1 будет вполне оправдано (TCNT1 может бежать синхронно с TCNT0, с известным соотношением).
2) Используйте глобальные переменные со словом "register", что даст Вам возможность хранить их значения в регистре а не памяти.

Вы также можете показать весь код, чтобы нам не фантазировать на тему оптимизации. В коде может быть довольно много подводных камней, которые можно убрать (ну, или наставить). Допустим, Вами представленный код может и не кешировать регистры в прерывании, если его правильно собрать (см.п.2, если не достаточно - то inline asm).
1
locm
30.10.2020, 12:26
  #10

Не по теме:

Цитата Сообщение от pusyakaryagin Посмотреть сообщение
подходит только стм32, но для такой простой задачи морально неудобно её использовать.
Вместо этого предпочитаете потратить побольше времени на оптимизацию и в конечном итоге может выяснится что время потрачено зря т. к. производительности недостаточно?

0
Тутошний я
2146 / 1201 / 225
Регистрация: 03.11.2009
Сообщений: 4,416
Записей в блоге: 2
30.10.2020, 12:55 11
Алгоритм был такой: если счетчик меньше уставки, то поднимаем единицу, а если больше, то опускаем.
зачем лишние такты?
досчитал до 16, все сбросил в 0.
а потом нужные подымаешь.

Добавлено через 1 минуту
а остальной код также оптимизирован?
0
1976 / 1275 / 130
Регистрация: 04.01.2010
Сообщений: 4,607
30.10.2020, 13:23 12
...если ШИМ не переключается часто - в памяти можно генерить паттерн из необходимых состояний и "проигрывать" его в цикле. Вот только в 13й тиньке сколько? 64 байт RAM всего? Маловато, как для красивого ШИМ. Но так сделать получится.
0
0 / 0 / 0
Регистрация: 01.03.2017
Сообщений: 27
30.10.2020, 14:02  [ТС] 13
Цитата Сообщение от Voland_ Посмотреть сообщение
используйте значение самогО таймера, для временнЫх тиков.
Идея классная, только в моём МК всего один таймер. Хотя есть варианты, но точного соотношения двух периодических прерываний тут не добиться. Можно попробовать вызывать прерывание каждый тик таймера (при каждом вызове инкрементируя число сравнения), но это добавит 3 такта на этот самый инкремент.
Цитата Сообщение от Voland_ Посмотреть сообщение
Используйте глобальные переменные со словом "register"
Это еще интереснее, только я не смог объявить глобальную переменную-регистр. В инете пишут, что регистром может быть только локальная переменная, но она ж нужна в прерывании.
Да, работаю (пока что) в Атмел Студии.

Не по теме:

Цитата Сообщение от locm Посмотреть сообщение
Вместо этого предпочитаете потратить побольше времени на оптимизацию
Не спорю, Вы совершенно правы, но работаю с тем, что есть. А то потом, когда мне понадобится 144 МГц, у меня будет 144 тиньки и ни одной стм.



Добавлено через 6 минут
Цитата Сообщение от Voland_ Посмотреть сообщение
...если ШИМ не переключается часто - в памяти можно генерить паттерн из необходимых состояний и "проигрывать" его в цикле. Вот только в 13й тиньке сколько? 64 байт RAM всего? Маловато, как для красивого ШИМ. Но так сделать получится.
Так и сделал, вот сейчас задача этот код перебора паттернов написать более-менее быстрым. 16 уровней мне хватит.
Цитата Сообщение от Grey Посмотреть сообщение
а остальной код также оптимизирован?
Нет)
Не думаю, что стоит ускорять код, у которого нет никаких временных ограничений. Только если ограничить его аппетиты в регистрах. Скоро покажу его, как только причешу.

Добавлено через 30 минут
А вот и весь код.
Кликните здесь для просмотра всего текста
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <stdbool.h>
 
#define F_CPU 9600000U
#include <util/delay.h>
 
#define PWM_RES 16 - 1
 
uint8_t adc;
//uint8_t adcs[4]={46,94,115,115}, values[20]={1,2,3,4,10,10,10,10,20,20,20,20,40,40,40,40,60,60,60,60}, freq=0;
uint8_t adcs[4], values[20], freq;
uint8_t pwm1=0,pwm2=0,pwm3=0,pwm4=0,flag=0,oldflag=0;
uint8_t port_out_table[16];
uint8_t cnt=0;
 
EEMEM uint8_t adcs_store[4] ;
EEMEM uint8_t values_store[20] ;
EEMEM uint8_t freq_store ;
 
//uint8_t flag_uart_error = 0;
 
 
uint8_t UART_receive(void)
// Receive one byte on hardcoded 9600 bps
{
    const uint8_t p = 49, P = p*2;
    volatile uint8_t usart_r=0;
    volatile uint8_t inbit = 0;
    
    while(PINB&(1<<4));
    _delay_us(P);
    for(uint8_t a=0; a<8; a++)
    {
        _delay_us(p);
        volatile int pinb = PINB;
        inbit = 1<<4;
        inbit = pinb & inbit;
        inbit = inbit>>4;
        usart_r |= (inbit << a);
        _delay_us(p);
    }
    _delay_us(P);
    //if( !(PINB&(1<<4)) ) flag_uart_error++;
    return usart_r;
}
 
 
ISR(TIM0_COMPA_vect)
// Timer interrupt handler
{
    PORTB = port_out_table[cnt];
    cnt == PWM_RES ? cnt = 0 : cnt++;
}
 
ISR(ADC_vect)
{
    adc=255-ADCH;
}
 
void boost(void)
// Blip fans before increasing speeds
{
    cli();
    PORTB = 0b00001111;
    _delay_ms(255);
    PORTB = 0;
    sei();
}
 
void beep_hi(uint16_t b)
{
    cli();
    while(b--)
    {
        _delay_us(450);
        PORTB = 0b00001111;
        _delay_us(50);
        PORTB = 0;
    }
    sei();
}
 
void beep_lo(uint16_t b)
{
    cli();
    while(b--)
    {
        _delay_us(900);
        PORTB = 0b00001111;
        _delay_us(100);
        PORTB = 0;
    }
    sei();
}
 
void newdelay(uint8_t in)
{
    while(in--) _delay_us(1);
}
 
void bitpeep()
// Beeps byte for debug reasons
{
    for(int t =0;t<4;t++)
    {
        uint8_t tmp = adcs[t];//UART_receiv();
        for(uint8_t i = 0; i<8; i++)
        {
            
            if(tmp&(1<<i)) beep_hi(500);
            else beep_lo(500);
            //tmp = tmp>>y;
            _delay_ms(500);
        }
    }
}
 
void read_settings_from_eep()
{
    for(uint8_t i = 0; i<4; i++)
    adcs[i] = eeprom_read_byte(&adcs_store[i]);
    for(uint8_t i = 0; i<20; i++)
    values[i] = eeprom_read_byte(&values_store[i]);
    freq = eeprom_read_byte(&freq_store);
}
 
void receive_settings_from_uart()
{
    cli();
    ADCSRA = 0;
    
    //Required input: 'saaaabbb...bbbce' - save 4a and 20b
    //If input: 'saaaabbb...bbbcn' - only load, not save
    
    if(UART_receive() == 's') // start block
    {
        for(uint8_t i = 0; i<4; i++)
        adcs[i]=UART_receive();
        for(uint8_t i = 0; i<20; i++)
        values[i]=UART_receive();
        freq = UART_receive();
        
        if(UART_receive() == 'e') // 'e' = write to eeprom
        {
            for(uint8_t i = 0; i<4; i++)
            eeprom_write_byte(&adcs_store[i], adcs[i]);
            for(uint8_t i = 0; i<20; i++)
            eeprom_write_byte(&values_store[i], values[i]);
            eeprom_write_byte(&freq_store, freq);
            //for(uint8_t h=3;h>0;h--)
            //{
            //beep_hi(200);
            //beep_lo(200);
            //_delay_ms(200);
            //}
        }
        
    }
    
    ADCSRA = 0xEA;
    sei();
}
 
int main(void)
{
    //register int cnt=0; // ???
    
    //DDRB&=~(1<<4); //input
    //DDRB|=(1<<0);  //outputs
    //DDRB|=(1<<1);
    //DDRB|=(1<<2);
    //DDRB|=(1<<3);
    DDRB=0b00001111;
    TCCR0A=(1<<WGM01); // clear at compare match
    TIMSK0=(1<<OCIE0A); // interrupt on compare match
    TCCR0B=(1<<CS00);
    OCR0A=60;
    
    //for(uint8_t i = 0; i<4; i++)
    //{
    //eeprom_write_byte(&adcs_store[i], adcs[i]);
    //}
    //for(uint8_t i = 0; i<20; i++)
    //eeprom_write_byte(&values_store[i], values[i]);
    //beep_hi(255);
    
    read_settings_from_eep();
    
    ADMUX = 0b00100010; // опорное напряжение - VCC
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);// 0b11101111;
    // АЦП включен, запуск преобразования, режим автоизмерения, прерывание по окончанию преобразования, частота CLK/128
    ADCSRB = 0x00; // режим автоизмерения: постоянно запущено
    //beep_lo(255);
    //boost();
    //boost();
    //boost();
    //beep_hi(255);
    
    asm("sei");
    
    while(1)
    {       
        // HIGH on input means uart connected
        if(0)//adc<=30) // DEBUG
        {
            receive_settings_from_uart();
        }
        
        newdelay(freq);
        
        oldflag=flag;
        
        // Setting the dependense of the settings on temperature
        // adc[0], 1, 2, 3 are thresholds
        if(adc<adcs[0])
        {
            pwm1=values[0];
            pwm2=values[1];
            pwm3=values[2];
            pwm4=values[3];
            flag=0;
        }
        else if(adc>adcs[0] && adc<adcs[1])
        {
            pwm1=values[4];
            pwm2=values[5];
            pwm3=values[6];
            pwm4=values[7];
            flag=1;
        }
        else if(adc>adcs[1] && adc<adcs[2])
        {
            pwm1=values[8];
            pwm2=values[9];
            pwm3=values[10];
            pwm4=values[11];
            flag=2;
        }
        else if(adc>adcs[2] && adc<adcs[3])
        {
            pwm1=values[12];
            pwm2=values[13];
            pwm3=values[14];
            pwm4=values[15];
            flag=3;
        }
        else if(adc>adcs[3])
        {
            pwm1=values[16];
            pwm2=values[17];
            pwm3=values[18];
            pwm4=values[19];
            flag=4;
        }
        if(flag>oldflag) boost();
        
        // PWM table setting. 
        volatile uint8_t u = 0; // костыль, чтоб цикл не выкидывался
        for(; u < PWM_RES; u++)
        {
            uint8_t tbl_tmp=0;
            if(u<pwm1) tbl_tmp |= (1<<0);
            else tbl_tmp &= ~(1<<0);
            if(u<pwm2) tbl_tmp |= (1<<1);
            else tbl_tmp &= ~(1<<1);
            if(u<pwm3) tbl_tmp |= (1<<2);
            else tbl_tmp &= ~(1<<2);
            if(u<pwm4) tbl_tmp |= (1<<3);
            else tbl_tmp &= ~(1<<3);
            
            port_out_table[u] = tbl_tmp;
            
        }       
    }
}
 
 
//}
0
Тутошний я
2146 / 1201 / 225
Регистрация: 03.11.2009
Сообщений: 4,416
Записей в блоге: 2
30.10.2020, 16:09 14
9600000/(20000*16)=30тактов
не получится шим 20 кГц. он постоянно будет в прерывание уходить.

10 кГц максимум. и uart в прерывание таймера поместить. задержки убрать.

Добавлено через 4 минуты
и пинов дофига задействовано. я бы взял atmega8. там хоть uart аппаратный есть.
0
4393 / 2243 / 252
Регистрация: 28.10.2011
Сообщений: 8,574
Записей в блоге: 6
30.10.2020, 16:14 15
Цитата Сообщение от Grey Посмотреть сообщение
я бы взял atmega8
Или 88/168/328. В них 6 аппаратных ШИМ.
0
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
30.10.2020, 16:21 16
pusyakaryagin, ещё вспомните (если не знали), что в AVR можно переключить состояние ноги-выхода за 1 такт, подав единицу в PIN.
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
30.10.2020, 19:39 17
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Тесты показали, что ШИМ на 10 Гц очень шумный, а вот немного сглаженый сигнал уже практически бесшумен. Нагрузка - обычные 3-pin вентиляторы.
ниче разбросы или 10 Герц или 20 килоГерц(сиречь 20000 Гц)
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Делаю охлаждение для серверов, чьи материнские платы не умеют управлять кулерами, а заказывать цифровой контроллер это большое время и гораздо дороже своей разработки.
делается все на паре операциоников, на одном генератор пилы на другом сравнение для 6 каналов хватит двух LM324
0
0 / 0 / 0
Регистрация: 01.03.2017
Сообщений: 27
30.10.2020, 22:16  [ТС] 18
Я с этим компилятором двинусь.
Оставил в обработчике прерывания один лишь NOP, а скомпилировалось вот такое:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
00000019  PUSH R1       Push register on stack 
0000001A  PUSH R0       Push register on stack 
0000001B  IN R0,0x3F        In from I/O location 
0000001C  PUSH R0       Push register on stack 
0000001D  CLR R1        Clear Register 
    asm volatile ( 
0000001E  NOP       No operation 
}
0000001F  POP R0        Pop register from stack 
00000020  OUT 0x3F,R0       Out to I/O location 
00000021  POP R0        Pop register from stack 
00000022  POP R1        Pop register from stack 
00000023  RETI      Interrupt return
(0х3F это SREG, и я понимаю, зачем он его сохраняет)
Вот как сделать так, чтобы я сам мог полностью написать обработчик на асме?
Уже набросал код на листочке, тактов 13-14 выходит, с учетом сохранения SREG, что так упорно пытается делать компилятор.

Добавлено через 6 минут
Цитата Сообщение от Kukuxumushu Посмотреть сообщение
в AVR можно переключить состояние ноги-выхода за 1 такт, подав единицу в PIN.
Помню такую штуку, но тут проще из памяти, где лежит таблица, вынуть байт и загрузить его в порт.
Цитата Сообщение от ValeryS Посмотреть сообщение
ниче разбросы или 10 Герц или 20 килоГерц
Ну да. Всё для бесшумности. Не у всех есть серверная для сервера)
Цитата Сообщение от ValeryS Посмотреть сообщение
делается все на паре операциоников
Люблю универсальные решения, и наверно время рассыпухи уже отходит. Там схема-то вышла - 4 ключа (можно два сдвоенных), счетверенный резистор, МК, притяжка сброса и 7805 с обвязкой. При желании можно развести на плате с 5р монетку.
Главное-то - настройка температурных порогов и уставок каналов через графическую утилиту с компа. Никакую логику так не настроишь.
0
Модератор
Эксперт по электронике
8908 / 6677 / 918
Регистрация: 14.02.2011
Сообщений: 23,521
30.10.2020, 22:47 19
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Всё для бесшумности.
а шум вентиляторов не учитываешь?
и частоту можешь опустить до пары килогерц, мотор просто не среагирует на такую частоту
0
1624 / 806 / 146
Регистрация: 13.06.2015
Сообщений: 3,266
30.10.2020, 22:50 20
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Я с этим компилятором двинусь.
С AVRstudio двинуться может кто угодно.
Цитата Сообщение от pusyakaryagin Посмотреть сообщение
Вот как сделать так, чтобы я сам мог полностью написать обработчик на асме?
Я вам уже советовал портироваться на CVAVR. Там это дело реализуется директивой #pragma savereg off перед шапкой прерывания. В итоге все прологи/эпилоги из листинга удаляются и вы спокойно можете сделать "чистую" asm-вставку. В хелпе всё подробно расписано (включая регистры, которые можно/нельзя тереть). Как реализовать такое в АВР-студии (и возможно ли вообще) - не имею понятия, т.к. работаю в ней чрезвычайно редко.
2
30.10.2020, 22:50
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.10.2020, 22:50
Помогаю со студенческими работами здесь

Оптимизация кода для повышения скорости выполнения?
Есть ли какая возможность в VBA замера производительности как в 1С с указанием относительного...

Оптимизация частоты ШИМа для управления приводами робота.
Из каких соображений можно определить оптимальную частоту ШИМ? При сильно низкой частоте двигатель...

Для повышения Тиц и Pr
Доброго времени суток, сколько ссылок должно ссылаться на мой сайт для повышения показателей Тиц и...

Определить частоты частости, накопленные частоты и частости для данных статистических данны
за 2003 год получены группировки доходов одного из акционерных обществ. Определить частоты ....

Фреймворк для повышения навыков PHP
Доброго времени суток. Хотел спросить у знающих людей какой фреймворк выбрать для изучения PHP....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru