Хитрые, необычные алгоритмы и код

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Встал на лапы
Сообщения: 88
Зарегистрирован: Ср апр 29, 2009 10:35:56
Откуда: кр. лиман украина

Сообщение culibin 100 »

добрый вечер господа!!!поделиться пока нечем но нужна помощь...суть такова ,что мне нужен алгоритм для реализации шим в атмега8 таймер 16ти битный , хочу использовать его выводы для управления оборотами двигателя..суть проблемы как реализовать дэад тайм?? буду использовать 2 канала .сигналы на выходе в противофазе.как работает таймер и режим шим я в курсе .спасибо за помощь.))пример на асм был бы тоже кстати для понимания :beer: :beer:
Реклама
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Просто задавать коэффициент заполнения так, чтобы каналы в сумме не давали 100% (255).

Например, один ШИМ-канал настраиваем как обычно, второй с инверсией, и задаем для одного значение ШИМ 120, а для другого 128, например. Получится защитный интервал в 8 отсчетов таймера, когда оба канала выключены.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Реклама
akl
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Можно так. Меняя значение 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
Встал на лапы
Сообщения: 88
Зарегистрирован: Ср апр 29, 2009 10:35:56
Откуда: кр. лиман украина

Сообщение culibin 100 »

спасибо огромное!! попробую что получиться
Реклама
Эиком - электронные компоненты и радиодетали
Встал на лапы
Сообщения: 88
Зарегистрирован: Ср апр 29, 2009 10:35:56
Откуда: кр. лиман украина

Сообщение culibin 100 »

график для понимания моей задачи
Вложения
график деад тайм.JPG
график для понимания моего вопроса
(14.45 КБ) 972 скачивания
Реклама
Встал на лапы
Сообщения: 88
Зарегистрирован: Ср апр 29, 2009 10:35:56
Откуда: кр. лиман украина

Сообщение culibin 100 »

блин чет я в тупике..сделал шим с корекцией фазы но тут проблема..мне надо еще менять частоту в пределах от 50 до 30гц.а в этом режиме никак..только разными коэфициентами деления таймера..деад тайм получается но тоже не важнецкий скважность не должна превышать 50%..что делать подскажите плиз
Реклама
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

А я снова о прерываниях.

Не всегда реакция на прерывание должна быть немедленной (мгновенной) Большей частью это не так. Чаще всего задержка от прерывания до реакции на него в десяток-другой команд ничего плохого за собой не влечет. Если задача укладывается в эти рамки, то есть возможность использовать общую программу обслуживания прерываний, которая сохраняет-восстатавливает 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 будет восстановлен позже,
; в общей программе, о нем заботиться не нужно.

Здесь RCALL INTEN - не вызов подпрограммы INTEN, а безусловный переход к ней с передачей в стеке параметра - адреса индивидуальной подпрограммы обслуживания этого конкретного прерывания, которая пишется после этого RCALL'а. Завершается она обычным RET'ом, после которого в общей программе будут восстановлены все регистры, включая SREG и сохраненный перед переходом к INTEN R16, после чего будет сделатн RETI.

Собственно, этот прием - разновидность использования сопрограмм, здесь индивидуальная подпрограмма обслуживания конкретного прерывания вызывается, как сопрограмма, на жаргоне тех времен говорили "засопрограммить". Так вот, "засопрограммить" ожидание прерывания в сложном драйвере какого-либо устройства - тоже очень плодотворный прием, например, при реализации сложного протокола передачи/приема данных через 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
В начале примера стоит обслуживание таймера Т0, который обеспечивает прерывания с частотой 256 Гц (кварц 14745600, прескалер 256), а далее - сама программа ожидания прерывания от USART'а. Она расчитана на "засопрограммленное" обслуживание входов в прервыание (та самая программа INTEN). Вот сильно урезанный кусочек моего проекта с использованием этой программы:
Спойлер

Код: Выделить всё

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

Для вызова этой программы помещаем адрес буфера в X и пишем

Код: Выделить всё

 cli
 rcall   ttyout
 sei
Сюда управление вернется сразу после первого вызова TOWait. Можно заниматься чем угодно, не трогая USART, R16, X и буфер с сообщением. Когда понадобится передавать новое сообщение, то следует дождаться, пока R16 не обнулится, после чего можно пересылать новое сообщение.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

akl писал(а):Здравствуйте. Недавно, на соседнем форуме был задан вопрос о быстром умножении 24-разрядных чисел. Было предложено использование алгоритма Дональда Кнута. В результате появился код, который выполняет
Умножение 24р*24р=48р выполняется за 75 тактов и занимает 65 слов
Умножение 32р*32р=64р выполняется за 134 такта и занимает 117 слов
Формат представления чисел старший-младший
Замечательно! А нет ли где-нибудь готового деления 64-разрядного числа на 32-разрядное, чтобы получить 32р частное и 32р остаток? Время некритично - хоть 100000 тактов.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
akl
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение akl »

Для 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
Друг Кота
Аватара пользователя
Сообщения: 15625
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

По АВРкину варианту... ( по посту 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
Правда это только в случае, ежли прерывание данного уровня не произойдет ранее, чем закончится его "хвост" обработки - иначе потребуется "флажковый семафор" для отработки "наложения в период исполнения".
:beer:
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

BOB51 писал(а):По АВРкину варианту... ( по посту afz )
Надо сначала прерывание текущего уровня закрыть, а уж затем на "хвост" переходить.
Ибо пока будет действовать текущее прерывание все другие прерывания будут недоступны.
Не всегда (далеко не всегда) это критично. Программа обслуживания конкретного прерывания, обычно, короткая - максимум - десяток-другой команд, а чаще всего - меньше. Большие же действия лучше исполнять "в фоне".
BOB51 писал(а): Т.Е. более оптимально подстановка адреса сопровождающей подпрограммы в стек и RETI с последующим RET из сопровождающей подпрограммы.
in rn,SREG
ldi r16,low (prog)
push r16
ldi r16,high (prog)
push r16
reti
Одначе там несколько нюансов по SREGу - запись не в стек, а в один из регистров регистрового файла
Зачем? Чем ему плохо в стеке? Если же задержка от прерывания до реакции на него сильно критична, то этим приемом лучше не пользоваться.
BOB51 писал(а): и на момент восстановления окантовка из
prog:
; собственно текст программы
CLI
out SREG,rn ; n=2-15
SEI
RET
Правда это только в случае, ежли прерывание данного уровня не произойдет ранее, чем закончится его "хвост" обработки - иначе потребуется "флажковый семафор" для отработки "наложения в период исполнения".
:beer:
Я бы в таком случае не стал открывать прерывания "для всех", то есть в общей части. Если уж приспичило их открыть, то это надо делать в индивидуальном обслуживании, предварительно сняв у устройства бит разрешения прерываний от него, а затем сделав SEI. Ну, и, окончив эти (длительные) действия сделал бы CLI, взвел бит разрешения прерываний от устройства и вышел. Естественно, такое можно делать только с устройствами, которые могут подождать. Но лучше, все-таки, перенести длительную обработку в фон.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Друг Кота
Аватара пользователя
Сообщения: 15625
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Почему "не в стек, а в тенёк"...
При переходе подстановкой адреса через стек - лишние сложности по определению места хранения статус-регистра.
Теперь насчет "почему открыто для всех"...
Собственно весь смысл такого приема быстрой реакции на прерывание и состотит в том, чтоб не занимать ресурс обработки прерываний при относительно длинном обработчике.
В противном случае зачем вообще перепрыгивать невесть куда внутри уже действующего прерывания с применением фокуса подстановки, если достаточно простого длинного перехода на обработчик расположенного в таблице векторов? А в конце прцедуры обработки банального RETI...
И лишние ячейки стека не занимаются и излишняя сложность перехода устранена.
Индексный CALL хорош в случае, если вектор прерывания всего один, а обслуживаемых источников несколько (аналогия среднемладших ПИКов). Поскольку у АВРок векторов в достатке, да еще и с некоторой приоритетностью ICALL для трюка прыжка на прикладной участок, да еще с непогашенным прерыванием... как-то излишне наворочено однако... :dont_know:
Друг Кота
Аватара пользователя
Сообщения: 20093
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Сообщение Gudd-Head »

Немного не в тему, ну да ладно.
Есть у меня любимая игрушка на Андроиде. И как все донатные игрушки она предоставляет выбор: жди или плати. Поскольку я жмот, я жду.
Заметил одну особенность: если подключиться к вайфаю на работе (а может, и не только?) время в выключенном состоянии начинает отсчитывать как-то странно:
Прихожу утром на работу, быстренько поиграю (просто запущу) с вайфаем, выключаю.
После рабочего дня если запустить без_доступа_интернета, окажется что в игре прошло... около 2-х часов. Но если включить инет, игровое время сразу скакнёт на 6 часов вперёд :)))
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

akl писал(а):Для AVR использую такую. Она, правда, примитивна как лом и, наверно, не очень смотрится в этой теме, но в качестве основы, думаю, пойдёт.
Я надеялся скопипастить... :)

А вот в начале (на первой странице) темы про асм авр таки нашлась полезная ссылка на ссылку на вот этот материал: http://elm-chan.org/cc_e.html, там в разделе AVR assembler libraries много вкусного. И можно скопипастить.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
Опытный кот
Аватара пользователя
Сообщения: 791
Зарегистрирован: Вт июн 17, 2014 00:34:26

Сообщение baghear »

Добрый день, хотелось бы понять как организованы предвыборки у dso138 - набор из которого можно собрать осциллограф. Вот часть схемы отвечающая за это
http://prntscr.com/7s49m7
А вот вся схема.
http://img.yunqudao.com/UploadFolder/4f ... /23_15.JPG
Так как оцифровка производится внутренним АЦП, то для быстрого сохранения надо использовать DMA. Алгоритм получения предвыборок следующий, наполняем половину буфера затем по срабатыванию триггера заполняем оставшуюся часть, в зависимости от настроек количество предвыборок и поствыборок может изменяться.
Надо отметить, что размер буфера DMA можно менять только при выключенyом DMA, поэтому на ходу изменять размер буфера не получится.

Может у кого-то есть идеи как это может быть реализовано?

Вопрос снят разобрался.
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Сообщение amd9800 »

baghear писал(а):Вопрос снят разобрался.
Тогда расскажите всем как разобрались.
Опытный кот
Аватара пользователя
Сообщения: 791
Зарегистрирован: Вт июн 17, 2014 00:34:26

Сообщение baghear »

А вот так
https://m.youtube.com/watch?v=YSC2J1qom2g
Заполняем нужную часть буффера игнорируя триггер, только потом начинаем заполнение буффера по триггеру, буфер кольцевой.
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Сообщение amd9800 »

Хочу проконсультироваться по поводу алгоритма.
Например с АЦП в 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

Сообщение baghear »

У Вас константа 360 000 полезное значение 36, остальные нули. Считайте в KAh, то есть КилоАмперЧасах, то же самое с Ваттами, а лучше спросите в ветке про С там подскажут, я только учусь.
Опытный кот
Сообщения: 822
Зарегистрирован: Вс июн 02, 2013 12:23:03

Сообщение amd9800 »

Вы наверное не правильно поняли меня? Притом вопрос адресован всем.
Что бы лучше понять посмотрите картинку.
Это дисплей на котором я вывожу информацию
Как видите выводится ампер часы с точностью до одной сотой.
Но этот счетчик постоянно тикает по мере чего реально ток течет через шунт.
Замеры тока делаю 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 скачиваний
Ответить

Вернуться в «Разные вопросы по МК»