Хитрые, необычные алгоритмы и код
добрый вечер господа!!!поделиться пока нечем но нужна помощь...суть такова ,что мне нужен алгоритм для реализации шим в атмега8 таймер 16ти битный , хочу использовать его выводы для управления оборотами двигателя..суть проблемы как реализовать дэад тайм?? буду использовать 2 канала .сигналы на выходе в противофазе.как работает таймер и режим шим я в курсе .спасибо за помощь.))пример на асм был бы тоже кстати для понимания

- Реклама
- Сообщения: 7518
- Зарегистрирован: Вс мар 29, 2009 22:09:05
Просто задавать коэффициент заполнения так, чтобы каналы в сумме не давали 100% (255).
Например, один ШИМ-канал настраиваем как обычно, второй с инверсией, и задаем для одного значение ШИМ 120, а для другого 128, например. Получится защитный интервал в 8 отсчетов таймера, когда оба канала выключены.
Например, один ШИМ-канал настраиваем как обычно, второй с инверсией, и задаем для одного значение ШИМ 120, а для другого 128, например. Получится защитный интервал в 8 отсчетов таймера, когда оба канала выключены.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Можно так. Меняя значение delta в диапазоне 4...508 будет изменение постоянной составляющей
Спойлер
Код: Выделить всё
.INCLUDE "m8def.inc"
.equ delta=8
.CSEG
.ORG $0000
START:
LDI R20,0b00000110
OUT DDRB,R20 ; начальный вывод 0
LDI R21,HIGH(512-delta)
OUT OCR1AH,R21
LDI R21,LOW(512-delta)
OUT OCR1AL,R21
LDI R21,HIGH(512+delta)
OUT OCR1BH,R21
LDI R21,LOW(512+delta)
OUT OCR1BL,R21
LDI R20,$B3 ; режим 10-bit PHASE CORRECT
OUT TCCR1A,R20
LDI R20,$01
OUT TCCR1B,R20
; каждые Fo/1024 формировать перепады на выходах PB2(OC1B) и PB1(OC1A)
; с защитным интервалом 2*delta тактов
RJMP PCграфик для понимания моей задачи
- Вложения
-
- график деад тайм.JPG
- график для понимания моего вопроса
- (14.45 КБ) 972 скачивания
- Реклама
блин чет я в тупике..сделал шим с корекцией фазы но тут проблема..мне надо еще менять частоту в пределах от 50 до 30гц.а в этом режиме никак..только разными коэфициентами деления таймера..деад тайм получается но тоже не важнецкий скважность не должна превышать 50%..что делать подскажите плиз
А я снова о прерываниях.
Не всегда реакция на прерывание должна быть немедленной (мгновенной) Большей частью это не так. Чаще всего задержка от прерывания до реакции на него в десяток-другой команд ничего плохого за собой не влечет. Если задача укладывается в эти рамки, то есть возможность использовать общую программу обслуживания прерываний, которая сохраняет-восстатавливает SREG и избранные регистры, а, при нужде, может и запустить селектор задач, переключить стек в вытесняющей многозадачке и т.п.
Сам прием я подсмотрел в недрах ядра RT-11. Конечно, на PDP-11 с ее разнообразием вариантов команды JSR это выглядит особо изящно, но и на любой платформе со стеком, доступным программно, хотя бы на уровне PUSH/POP, все и выглядит и работает нормально.
Вот реализация для AVR:
Используется это так:
Здесь RCALL INTEN - не вызов подпрограммы INTEN, а безусловный переход к ней с передачей в стеке параметра - адреса индивидуальной подпрограммы обслуживания этого конкретного прерывания, которая пишется после этого RCALL'а. Завершается она обычным RET'ом, после которого в общей программе будут восстановлены все регистры, включая SREG и сохраненный перед переходом к INTEN R16, после чего будет сделатн RETI.
Собственно, этот прием - разновидность использования сопрограмм, здесь индивидуальная подпрограмма обслуживания конкретного прерывания вызывается, как сопрограмма, на жаргоне тех времен говорили "засопрограммить". Так вот, "засопрограммить" ожидание прерывания в сложном драйвере какого-либо устройства - тоже очень плодотворный прием, например, при реализации сложного протокола передачи/приема данных через USART. Вместо могучего switch'а, который разбирается, куда надо идти, получив очередное прерывание, пишем простую линейную или разветвленную программу, а в месте, где требуется подождать очередного прерывания, пишем, допустим, RCALL TOWait, а эта "подпрограмма" сохранит в статической памяти все, что надо, включая адрес возврата в вызвавшую ее программу и выйдет из прерывания. Затем, когда произойдет прерывание, вторая часть этой "подпрограммы" восстановит све сохраненное ее первой частью и перейдет по сохраненному адресу, то есть на команду, следующую за тем самым RCALL TOWait. Вот, опять же, пример для AVR:
В начале примера стоит обслуживание таймера Т0, который обеспечивает прерывания с частотой 256 Гц (кварц 14745600, прескалер 256), а далее - сама программа ожидания прерывания от USART'а. Она расчитана на "засопрограммленное" обслуживание входов в прервыание (та самая программа INTEN). Вот сильно урезанный кусочек моего проекта с использованием этой программы:
Для вызова этой программы помещаем адрес буфера в X и пишем
Сюда управление вернется сразу после первого вызова TOWait. Можно заниматься чем угодно, не трогая USART, R16, X и буфер с сообщением. Когда понадобится передавать новое сообщение, то следует дождаться, пока R16 не обнулится, после чего можно пересылать новое сообщение.
Не всегда реакция на прерывание должна быть немедленной (мгновенной) Большей частью это не так. Чаще всего задержка от прерывания до реакции на него в десяток-другой команд ничего плохого за собой не влечет. Если задача укладывается в эти рамки, то есть возможность использовать общую программу обслуживания прерываний, которая сохраняет-восстатавливает SREG и избранные регистры, а, при нужде, может и запустить селектор задач, переключить стек в вытесняющей многозадачке и т.п.
Сам прием я подсмотрел в недрах ядра RT-11. Конечно, на PDP-11 с ее разнообразием вариантов команды JSR это выглядит особо изящно, но и на любой платформе со стеком, доступным программно, хотя бы на уровне PUSH/POP, все и выглядит и работает нормально.
Вот реализация для AVR:
Спойлер
Код: Выделить всё
; Общий вход в прерывания.
; Перед вызовом сохранить R16
; Здесь сохраняются SREG, R17,18, X и Z
IntEn:
pop r16 ; Достаем адрес возврата
sts reta1,r16 ; из стека и сохраняем его
pop r16 ; в статической памяти.
sts reta1+1,r16 ; Прерывания здесь закрыты,
; reta1, если где и использую,
; то тоже при закрытых прерываниях
; Далее сохраняемся
in r16,SREG;
push r16
push r17
push r18
push xh
push xl
push zh
push zl
lds zh,reta1 ; и вызовем продолжение, как сопрограмму.
lds zl,reta1+1 ; Оно закончится ret'ом, после его выполнения
icall ; вернемся сюда.
; Восстановимся
pop zl
pop zh
pop xl
pop xh
pop r18
pop r17
pop r16
out SREG,r16
; Восстановим R16, сохраненный перед вызовом inten
pop r16
reti ; и чао-какао!
Код: Выделить всё
Interrupt_Label: ; Сюда ссылается один из (r)jmp из таблицы векторов
push r16
rcall inten
... ; Здесь располагается индивидуальная программа обслуживания
... ; этого конкретного прерывания
ret ; Заканчивается она RET'ом, а не RETI. Регистр R16 будет восстановлен позже,
; в общей программе, о нем заботиться не нужно.
Собственно, этот прием - разновидность использования сопрограмм, здесь индивидуальная подпрограмма обслуживания конкретного прерывания вызывается, как сопрограмма, на жаргоне тех времен говорили "засопрограммить". Так вот, "засопрограммить" ожидание прерывания в сложном драйвере какого-либо устройства - тоже очень плодотворный прием, например, при реализации сложного протокола передачи/приема данных через USART. Вместо могучего switch'а, который разбирается, куда надо идти, получив очередное прерывание, пишем простую линейную или разветвленную программу, а в месте, где требуется подождать очередного прерывания, пишем, допустим, RCALL TOWait, а эта "подпрограмма" сохранит в статической памяти все, что надо, включая адрес возврата в вызвавшую ее программу и выйдет из прерывания. Затем, когда произойдет прерывание, вторая часть этой "подпрограммы" восстановит све сохраненное ее первой частью и перейдет по сохраненному адресу, то есть на команду, следующую за тем самым RCALL TOWait. Вот, опять же, пример для AVR:
Спойлер
Код: Выделить всё
TIM0_OVF: ; Timer0 Overflow Handler
push r16
rcall inten
ldi r16,(256-225)
out TCNT0,R16
lds r16,T0OflCnt
inc r16
sts T0OflCnt,r16
tst r16
brne L2
nop
nop
L2: ret
TOWait:
sts toDadr,XL
sts toDadr+1,XH
sts towfg,r16
pop r16
sts toRadr,r16
pop R16
sts toRadr+1,r16
ret
USART_UDRE: ; UDR Empty Handler
push r16
rcall inten
lds zh,toRadr
lds zl,toRadr+1
lds xl,toDadr
lds xh,toDadr+1
ijmp
Спойлер
Код: Выделить всё
TTYOUT: ; Первый вызов - синхронный
ldi r16,1 ; Взведем флаг "Есть данные на передачу"
sbi UCSRB,UDRIE ; разрешим прерывание для передачи данных через USART
rcall towait ; и вызываем "ожидание". На самом деле это выход из
; программы, сюда вернемся асинхронно, после прерывания
ldi r17,1 ; Передадим заголовок
out udr,r17 ; (байты 0x01, 0x00)
ldi r17,0 ;
out udr,r17 ;
; А это - цикл побайтовой передачи данных из буфера (Х), в конце - 0x00
tto1:
ld r16,x+
tst r16
brne tto2
cbi UCSRB,UDRIE
rjmp tto3
tto2: out udr,r16
tto3: rcall towait
rjmp tto1
Код: Выделить всё
cli
rcall ttyout
seiКто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Замечательно! А нет ли где-нибудь готового деления 64-разрядного числа на 32-разрядное, чтобы получить 32р частное и 32р остаток? Время некритично - хоть 100000 тактов.akl писал(а):Здравствуйте. Недавно, на соседнем форуме был задан вопрос о быстром умножении 24-разрядных чисел. Было предложено использование алгоритма Дональда Кнута. В результате появился код, который выполняет
Умножение 24р*24р=48р выполняется за 75 тактов и занимает 65 слов
Умножение 32р*32р=64р выполняется за 134 такта и занимает 117 слов
Формат представления чисел старший-младший
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Для AVR использую такую. Она, правда, примитивна как лом и, наверно, не очень смотрится в этой теме, но в качестве основы, думаю, пойдёт.
Спойлер
Код: Выделить всё
; Программа деления 78 разрядного числа на 78 разрядное число
; R0...R9-ДЕЛИМОЕ, R10...R19-ДЕЛИТЕЛЬ!!!!R0...R9-РЕЗУЛЬТАТ
; R20...R29-РЕЗУЛЬТАТ,ZL-TEMP, ZH-ZERO
;**********************************************************************
GDIV_ERROR:
SET
GDIV_OUT2:
RET
DIV:
CLT ; сбос флага ошибки, если это не было сделано при входе в программу
CLR ZH ; zero-регистр
CLR R20
CLR R21
CLR R22
CLR R23
CLR R24
CLR R25
CLR R26
CLR R27
CLR R28
CLR R29 ; начальное значение результата
;**********************************************************************
; проверка области допустимых значений делимого и делителя
TST R0
BRMI GDIV_ERROR ; делимое отрицательное, ERROR
CP R19,R29
CPC R18,R28
CPC R17,R27
CPC R16,R26
CPC R15,R25
CPC R14,R24
CPC R13,R23
CPC R12,R22
CPC R11,R21
CPC R10,R20
BREQ GDIV_ERROR ; YES,DELITEL=0, ERROR
CP R29,R9
CPC R28,R8
CPC R27,R7
CPC R26,R6
CPC R25,R5
CPC R24,R4
CPC R23,R3
CPC R22,R2
CPC R21,R1
CPC R20,R0
BREQ GDIV_OUT2 ; YES,DELIMOE=0, REZULTAT=0
CP R9,R19
CPC R8,R18
CPC R7,R17
CPC R6,R16
CPC R5,R15
CPC R4,R14
CPC R3,R13
CPC R2,R12
CPC R1,R11
CPC R0,R10
BRPL DIV_GO1 ; NO, DELITEL<DELIMOGO
RJMP DIV_OUT1
DIV_GO1:
BRNE DIV_GO
RJMP DIV_EQU ; делитель=делимому, результат=1
;***************************************************************************
; выравнивание порядков делителя с делимым
;***************************************************************************
DIV_GO:
CLR ZL ; очистить счетчик сдвигов
DIV1:
CP R19,R9
CPC R18,R8
CPC R17,R7
CPC R16,R6
CPC R15,R5
CPC R14,R4
CPC R13,R3
CPC R12,R2
CPC R11,R1
CPC R10,R0
BRCC DIV2 ; YES,DELITEL>DELIMOGO
LSL R19
ROL R18
ROL R17
ROL R16
ROL R15
ROL R14
ROL R13
ROL R12
ROL R11
ROL R10 ; DELITEL*2
INC ZL
CPI ZL,80
BRNE DIV1
;***************************************************************************
; порядкок делителя найден с превышением
;***************************************************************************
DIV2:
T_DIV0:
CLT
LSL R9
ROL R8
ROL R7
ROL R6
ROL R5
ROL R4
ROL R3
ROL R2
ROL R1
ROL R0 ; делимое или остаток*2
CP R19,R9
CPC R18,R8
CPC R17,R7
CPC R16,R6
CPC R15,R5
CPC R14,R4
CPC R13,R3
CPC R12,R2
CPC R11,R1
CPC R10,R0 ; делитель больше делимого ?
BRCS T_DIV20 ; да,оставляем в 0 сооответствующий разряд результата
SET ; нет, взвести в 1 сооответствующий разряд результата
T_DIV20:
ROL R29
ROL R28
ROL R27
ROL R26
ROL R25
ROL R24
ROL R23
ROL R22
ROL R21
ROL R20
BRTS T_DIV40
SUB R9,R19
SBC R8,R18
SBC R7,R17
SBC R6,R16
SBC R5,R15
SBC R4,R14
SBC R3,R13
SBC R2,R12
SBC R1,R11
SBC R0,R10
T_DIV40:
DEC ZL
BRNE T_DIV0
;***************************************************************************
; проверка остатка для округления результата
DIV_OUT:
LSL R9
ROL R8
ROL R7
ROL R6
ROL R5
ROL R4
ROL R3
ROL R2
ROL R1
ROL R0 ; остаток*2 или 0.ххх*2
CP R9,R19
CPC R8,R18
CPC R7,R17
CPC R6,R16
CPC R5,R15
CPC R4,R14
CPC R3,R13
CPC R2,R12
CPC R1,R11
CPC R0,R10 ; делитель больше остатка или остаток >0.5 ?
BRCS DIV_OUT1 ; нет, остаток <0.5
; да остаток > 0.5, добавить 1
;***************************************************************************
DIV_EQU:
SEC
ADC R29,ZH
ADC R28,ZH
ADC R27,ZH
ADC R26,ZH
ADC R25,ZH
ADC R24,ZH
ADC R23,ZH
ADC R22,ZH
ADC R21,ZH
ADC R20,ZH
DIV_OUT1:
MOV R0,R20
MOV R1,R21
MOV R2,R22
MOV R3,R23
MOV R4,R24
MOV R5,R25
MOV R6,R26
MOV R7,R27
MOV R8,R28
MOV R9,R29
CLT
RET
;END
По АВРкину варианту... ( по посту afz )
Надо сначала прерывание текущего уровня закрыть, а уж затем на "хвост" переходить.
Ибо пока будет действовать текущее прерывание все другие прерывания будут недоступны.
Т.Е. более оптимально подстановка адреса сопровождающей подпрограммы в стек и RETI с последующим RET из сопровождающей подпрограммы.
in rn,SREG
ldi r16,low (prog)
push r16
ldi r16,high (prog)
push r16
reti
Одначе там несколько нюансов по SREGу - запись не в стек, а в один из регистров регистрового файла и на момент восстановления окантовка из
prog:
; собственно текст программы
CLI
out SREG,rn ; n=2-15
SEI
RET
Правда это только в случае, ежли прерывание данного уровня не произойдет ранее, чем закончится его "хвост" обработки - иначе потребуется "флажковый семафор" для отработки "наложения в период исполнения".

Надо сначала прерывание текущего уровня закрыть, а уж затем на "хвост" переходить.
Ибо пока будет действовать текущее прерывание все другие прерывания будут недоступны.
Т.Е. более оптимально подстановка адреса сопровождающей подпрограммы в стек и RETI с последующим RET из сопровождающей подпрограммы.
in rn,SREG
ldi r16,low (prog)
push r16
ldi r16,high (prog)
push r16
reti
Одначе там несколько нюансов по SREGу - запись не в стек, а в один из регистров регистрового файла и на момент восстановления окантовка из
prog:
; собственно текст программы
CLI
out SREG,rn ; n=2-15
SEI
RET
Правда это только в случае, ежли прерывание данного уровня не произойдет ранее, чем закончится его "хвост" обработки - иначе потребуется "флажковый семафор" для отработки "наложения в период исполнения".
Не всегда (далеко не всегда) это критично. Программа обслуживания конкретного прерывания, обычно, короткая - максимум - десяток-другой команд, а чаще всего - меньше. Большие же действия лучше исполнять "в фоне".BOB51 писал(а):По АВРкину варианту... ( по посту afz )
Надо сначала прерывание текущего уровня закрыть, а уж затем на "хвост" переходить.
Ибо пока будет действовать текущее прерывание все другие прерывания будут недоступны.
Зачем? Чем ему плохо в стеке? Если же задержка от прерывания до реакции на него сильно критична, то этим приемом лучше не пользоваться.BOB51 писал(а): Т.Е. более оптимально подстановка адреса сопровождающей подпрограммы в стек и RETI с последующим RET из сопровождающей подпрограммы.
in rn,SREG
ldi r16,low (prog)
push r16
ldi r16,high (prog)
push r16
reti
Одначе там несколько нюансов по SREGу - запись не в стек, а в один из регистров регистрового файла
Я бы в таком случае не стал открывать прерывания "для всех", то есть в общей части. Если уж приспичило их открыть, то это надо делать в индивидуальном обслуживании, предварительно сняв у устройства бит разрешения прерываний от него, а затем сделав SEI. Ну, и, окончив эти (длительные) действия сделал бы CLI, взвел бит разрешения прерываний от устройства и вышел. Естественно, такое можно делать только с устройствами, которые могут подождать. Но лучше, все-таки, перенести длительную обработку в фон.BOB51 писал(а): и на момент восстановления окантовка из
prog:
; собственно текст программы
CLI
out SREG,rn ; n=2-15
SEI
RET
Правда это только в случае, ежли прерывание данного уровня не произойдет ранее, чем закончится его "хвост" обработки - иначе потребуется "флажковый семафор" для отработки "наложения в период исполнения".
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Почему "не в стек, а в тенёк"...
При переходе подстановкой адреса через стек - лишние сложности по определению места хранения статус-регистра.
Теперь насчет "почему открыто для всех"...
Собственно весь смысл такого приема быстрой реакции на прерывание и состотит в том, чтоб не занимать ресурс обработки прерываний при относительно длинном обработчике.
В противном случае зачем вообще перепрыгивать невесть куда внутри уже действующего прерывания с применением фокуса подстановки, если достаточно простого длинного перехода на обработчик расположенного в таблице векторов? А в конце прцедуры обработки банального RETI...
И лишние ячейки стека не занимаются и излишняя сложность перехода устранена.
Индексный CALL хорош в случае, если вектор прерывания всего один, а обслуживаемых источников несколько (аналогия среднемладших ПИКов). Поскольку у АВРок векторов в достатке, да еще и с некоторой приоритетностью ICALL для трюка прыжка на прикладной участок, да еще с непогашенным прерыванием... как-то излишне наворочено однако...
При переходе подстановкой адреса через стек - лишние сложности по определению места хранения статус-регистра.
Теперь насчет "почему открыто для всех"...
Собственно весь смысл такого приема быстрой реакции на прерывание и состотит в том, чтоб не занимать ресурс обработки прерываний при относительно длинном обработчике.
В противном случае зачем вообще перепрыгивать невесть куда внутри уже действующего прерывания с применением фокуса подстановки, если достаточно простого длинного перехода на обработчик расположенного в таблице векторов? А в конце прцедуры обработки банального RETI...
И лишние ячейки стека не занимаются и излишняя сложность перехода устранена.
Индексный CALL хорош в случае, если вектор прерывания всего один, а обслуживаемых источников несколько (аналогия среднемладших ПИКов). Поскольку у АВРок векторов в достатке, да еще и с некоторой приоритетностью ICALL для трюка прыжка на прикладной участок, да еще с непогашенным прерыванием... как-то излишне наворочено однако...
Немного не в тему, ну да ладно.
Есть у меня любимая игрушка на Андроиде. И как все донатные игрушки она предоставляет выбор: жди или плати. Поскольку я жмот, я жду.
Заметил одну особенность: если подключиться к вайфаю на работе (а может, и не только?) время в выключенном состоянии начинает отсчитывать как-то странно:
Прихожу утром на работу, быстренько поиграю (просто запущу) с вайфаем, выключаю.
После рабочего дня если запустить без_доступа_интернета, окажется что в игре прошло... около 2-х часов. Но если включить инет, игровое время сразу скакнёт на 6 часов вперёд
Есть у меня любимая игрушка на Андроиде. И как все донатные игрушки она предоставляет выбор: жди или плати. Поскольку я жмот, я жду.
Заметил одну особенность: если подключиться к вайфаю на работе (а может, и не только?) время в выключенном состоянии начинает отсчитывать как-то странно:
Прихожу утром на работу, быстренько поиграю (просто запущу) с вайфаем, выключаю.
После рабочего дня если запустить без_доступа_интернета, окажется что в игре прошло... около 2-х часов. Но если включить инет, игровое время сразу скакнёт на 6 часов вперёд
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Я надеялся скопипастить...akl писал(а):Для AVR использую такую. Она, правда, примитивна как лом и, наверно, не очень смотрится в этой теме, но в качестве основы, думаю, пойдёт.
А вот в начале (на первой странице) темы про асм авр таки нашлась полезная ссылка на ссылку на вот этот материал: http://elm-chan.org/cc_e.html, там в разделе AVR assembler libraries много вкусного. И можно скопипастить.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
Добрый день, хотелось бы понять как организованы предвыборки у dso138 - набор из которого можно собрать осциллограф. Вот часть схемы отвечающая за это
http://prntscr.com/7s49m7
А вот вся схема.
http://img.yunqudao.com/UploadFolder/4f ... /23_15.JPG
Так как оцифровка производится внутренним АЦП, то для быстрого сохранения надо использовать DMA. Алгоритм получения предвыборок следующий, наполняем половину буфера затем по срабатыванию триггера заполняем оставшуюся часть, в зависимости от настроек количество предвыборок и поствыборок может изменяться.
Надо отметить, что размер буфера DMA можно менять только при выключенyом DMA, поэтому на ходу изменять размер буфера не получится.
Может у кого-то есть идеи как это может быть реализовано?
Вопрос снят разобрался.
http://prntscr.com/7s49m7
А вот вся схема.
http://img.yunqudao.com/UploadFolder/4f ... /23_15.JPG
Так как оцифровка производится внутренним АЦП, то для быстрого сохранения надо использовать DMA. Алгоритм получения предвыборок следующий, наполняем половину буфера затем по срабатыванию триггера заполняем оставшуюся часть, в зависимости от настроек количество предвыборок и поствыборок может изменяться.
Надо отметить, что размер буфера DMA можно менять только при выключенyом DMA, поэтому на ходу изменять размер буфера не получится.
Может у кого-то есть идеи как это может быть реализовано?
Вопрос снят разобрался.
- Сообщения: 822
- Зарегистрирован: Вс июн 02, 2013 12:23:03
Тогда расскажите всем как разобрались.baghear писал(а):Вопрос снят разобрался.
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
А вот так
https://m.youtube.com/watch?v=YSC2J1qom2g
Заполняем нужную часть буффера игнорируя триггер, только потом начинаем заполнение буффера по триггеру, буфер кольцевой.
https://m.youtube.com/watch?v=YSC2J1qom2g
Заполняем нужную часть буффера игнорируя триггер, только потом начинаем заполнение буффера по триггеру, буфер кольцевой.
- Сообщения: 822
- Зарегистрирован: Вс июн 02, 2013 12:23:03
Хочу проконсультироваться по поводу алгоритма.
Например с АЦП в 10 битном формате я снимаю два значения.
Ток и Напряжение. Каждое значение снимаю, к примеру 100 раз за секунду.
Данные надо накапливать в счетчик по Ah и по wh.
Счетчик Аh переменная Unsigned int А - хранит ампер часы
Unsigned char D хранит сотые ампера. Когда D отсчитала 100, А++, а D=0
Каждую 1/100 данные.
Одна сотая Аh = 3600*(АЦП значение 1A) если значение 1А = 100 тогда Константа будет 360 000
Теперь мы в переменную каждую сотую секунду будем накапливать значение АЦП, если она перевалит за 360 000
D++, а из переменной мы вычитаем 360 000.
Первая проблема константа вылазит за размерами Int - это создает нагрузку на маленький АВР
Вторая проблема чтоб считать wh потому что и так большую константу надо умножать на напряжение.
Как мне оптимизировать алгоритм для АВР?
Например с АЦП в 10 битном формате я снимаю два значения.
Ток и Напряжение. Каждое значение снимаю, к примеру 100 раз за секунду.
Данные надо накапливать в счетчик по Ah и по wh.
Счетчик Аh переменная Unsigned int А - хранит ампер часы
Unsigned char D хранит сотые ампера. Когда D отсчитала 100, А++, а D=0
Каждую 1/100 данные.
Одна сотая Аh = 3600*(АЦП значение 1A) если значение 1А = 100 тогда Константа будет 360 000
Теперь мы в переменную каждую сотую секунду будем накапливать значение АЦП, если она перевалит за 360 000
D++, а из переменной мы вычитаем 360 000.
Первая проблема константа вылазит за размерами Int - это создает нагрузку на маленький АВР
Вторая проблема чтоб считать wh потому что и так большую константу надо умножать на напряжение.
Как мне оптимизировать алгоритм для АВР?
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
У Вас константа 360 000 полезное значение 36, остальные нули. Считайте в KAh, то есть КилоАмперЧасах, то же самое с Ваттами, а лучше спросите в ветке про С там подскажут, я только учусь.
- Сообщения: 822
- Зарегистрирован: Вс июн 02, 2013 12:23:03
Вы наверное не правильно поняли меня? Притом вопрос адресован всем.
Что бы лучше понять посмотрите картинку.
Это дисплей на котором я вывожу информацию
Как видите выводится ампер часы с точностью до одной сотой.
Но этот счетчик постоянно тикает по мере чего реально ток течет через шунт.
Замеры тока делаю 100 раз в секунду.
Значение может быть от 0 до 1023 в 10 битном формате.
Дальше предположим что в результате калибровки я выяснил что при значение 100 это ток в 1А. Но один ампер может быть и 99 и 102. На разных девайсах значение может немножко отличатся.
А в течение одно часа это 3600сек * 100измерений в сек = получаем 360 000 измерений за час
А значение 1А = 100 АЦП значений тогда получается что 1 Ампер час равняется 360 000 * 100 = 36 000 000 АЦП значений
Но поскольку 0.01 Аh это одна сотая ампера то это в 100 раз меньше.
То есть 360 000 АЦП значений равняется одной сотой ампера. Но это при условии что 1 = 100 АЦП значений
если 1 А = 130 АЦП значений, тогда 0.01Ah = 468 000 АЦП значений
как все работает допустим то 2,3А в момент измерения = 230 АЦП значений - суммируем
следующее измерение 235 - суммируем
следующее измерение 250 - суммируем
следующее измерение 295 - суммируем
и так далее
и каждый раз сравниваем сумму с 360 000
Если сумма перевалила за 360 000 тогда сумма = сумма - 360 000
а сотые Ah увеличивается на одно значение.
и продолжаем дальше.
Поскольку 360 000 больше 65535 это получается уже переменная типа long, а с такой переменной МК 8бит пахать и пахать
суммировать и сравнивать - мучительные операции. Вот и думаю как улучшить алгоритм.

Что бы лучше понять посмотрите картинку.
Это дисплей на котором я вывожу информацию
Как видите выводится ампер часы с точностью до одной сотой.
Но этот счетчик постоянно тикает по мере чего реально ток течет через шунт.
Замеры тока делаю 100 раз в секунду.
Значение может быть от 0 до 1023 в 10 битном формате.
Дальше предположим что в результате калибровки я выяснил что при значение 100 это ток в 1А. Но один ампер может быть и 99 и 102. На разных девайсах значение может немножко отличатся.
А в течение одно часа это 3600сек * 100измерений в сек = получаем 360 000 измерений за час
А значение 1А = 100 АЦП значений тогда получается что 1 Ампер час равняется 360 000 * 100 = 36 000 000 АЦП значений
Но поскольку 0.01 Аh это одна сотая ампера то это в 100 раз меньше.
То есть 360 000 АЦП значений равняется одной сотой ампера. Но это при условии что 1 = 100 АЦП значений
если 1 А = 130 АЦП значений, тогда 0.01Ah = 468 000 АЦП значений
как все работает допустим то 2,3А в момент измерения = 230 АЦП значений - суммируем
следующее измерение 235 - суммируем
следующее измерение 250 - суммируем
следующее измерение 295 - суммируем
и так далее
и каждый раз сравниваем сумму с 360 000
Если сумма перевалила за 360 000 тогда сумма = сумма - 360 000
а сотые Ah увеличивается на одно значение.
и продолжаем дальше.
Поскольку 360 000 больше 65535 это получается уже переменная типа long, а с такой переменной МК 8бит пахать и пахать
суммировать и сравнивать - мучительные операции. Вот и думаю как улучшить алгоритм.
- Вложения
-
- lcd-ah.PNG
- (2.48 КБ) 1485 скачиваний


