Перейти к содержанию

Вопросы от начинающих по МК


Рекомендуемые сообщения

Добрый вечер!

Краткое описание работы программы:

по нажатию кнопки, которая подключена к 3-му пину порта D (отсчёт начинает с нуля) , увеличивается содержимое регистра REG2, в зависимости от его содержимого, выводится тот или иной результат измерения АЦП на дисплей. При включении МК (мега32а)АЦП по очереди начинает циклически измерять напряжение на входах ADC0, ADC, ADC2 и вновь ADC0, сохраняя результат каждого преобразования в соответствующем регистре result_in_volt, result_out_volt, result_in_current. А при каждом измерении канала ADC0 выводит в порт С определённую комбинацию. Дисплей подключен к порту В и PD1, PD2, PD3 (динамическая индикация), а комбинация выводится в порт С.

Проблема в следующем:

МК не реагирует на нажатие кнопки, то есть как мерил и выводил канал ADC0 на дисплей, так и выводит, хотя писал другую программку для теста кнопки, она работала, а вот в связке с АЦП не хочет работать, понимаю что программа большая и с ходу возможно разобраться трудно, но может кто подскажет на ошибки, в чем может быть дело?

Текст программы:

.device ATmega32A
.include "C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes\m32Adef.inc"
; СЕМИСЕГМЕНТНЫЕ ИНДИКАТОРЫ ПОДКЛЮЧЕНЫ К ПОРТУ "В" В ПОРЯДКЕ "abcdefg"




                    ;==== ОПРЕДЕЛЕНИЕ ИМЁН РЕГИСТРОВ ====

.def Hundreds=R2				;
.def Tens=R3					;
.def Ones=R4					;
.def temp=R16					;
.def indication_out=R17			;
.def counterADC=R18				;
.def Delay1=R19					;   
.def REG1=R20					;
.def numbersigment=R21			;
.def result=R22					;
.def control=R23				;
.def result_in_volt=R24			;
.def result_out_volt=R25		;
.def result_in_current=R26		;
.def REG2=R27					;
.def Delay2=R28					;











				 ;==== ЗАДАНИЕ ВЕКТОРА ПРЕРЫВАНИЙ ====

.cseg                             ; выбор сегмента программного кода

.org 0                            ; установка текущего адреса на ноль
			jmp RESET;

.org INT0addr                     ; Внешнее прерывание 0
			nop;

.org INT1addr                     ; Внешнее прерывание 1
			nop;

.org INT2addr                     ; Внешнее прерывание 2
			nop;

.org OC2addr                      ; Совпадение таймера/счётчика Т2
			nop;

.org OVF2addr                     ; Переполнение таймера/счётчика Т2
			nop;

.org ICP1addr                     ; Захват таймера/счётчика Т1
			nop;

.org OC1Aaddr                     ; Совпадение А таймера/счётчика Т1
			nop;

.org OC1Baddr                     ; Совпадение В таймера/счётчика Т1
			nop;

.org OVF1addr                     ; Переполнение таймера/счётчика Т1
			nop;

.org OC0addr                      ; Совпадение таймера/счётчика Т0
			jmp Timer0;

.org OVF0addr                     ; Переполнение тамймера/счётчика Т0
			nop;

.org SPIaddr                      ; Передача по SPI завершена
			nop;

.org URXCaddr                     ; USART, приём завершён
			nop;

.org UDREaddr                     ; Регистр данных USART пуст
			nop;

.org UTXCaddr                     ; USART, передача завершена
			nop;

.org ADCCaddr                     ; Преобразование АЦП завершено
			jmp Chenal        ; При генерации прерывания по окончанию 
                                 ; АЦ преобразования программа переходит к подпрограмме 
			                  ;вычисления отклонения

.org ERDYaddr                     ; EEPROM готово
			nop;

.org ACIaddr                      ; Аналоговый компаратор
			nop;

.org TWIaddr                      ; Прерывание от модуля TWI
			nop;

.org SPMRaddr                     ; Готовность SPM
			nop;

.org $60                          ; установка текущего адреса программного кода на 60









RESET:

               ;==== ИНИЦИАЛИЗАЦИЯ СТЕКА ====

			ldi temp,low(RAMEND)             ; загрузка младшего байта указателя стека
			out SPL,temp;
			ldi temp,high(RAMEND)            ; загрузка старшего байта указателя стека
			out SPH,temp;

			;==== ЗАВЕРШЕНО ====





			;==== КОНФИГУРИРОВАНИЕ СТОРОЖЕВОГО ТАЙМЕРА ====
			wdr;
			in temp,WDTCR;
			ori temp,(1<<WDTOE)|(1<<WDE); 
			out WDTCR,temp;
			ldi temp,(0<<WDE);
			out WDTCR,temp                   ; остановка сторожевого таймера

			;==== ЗАВЕРШЕНО ====





			;==== ИНИЦИАЛИЗАЦИЯ ПОРТОВ ВВОДА/ВЫВОДА ====


               ;---- НАСТРОЙКА ПОРТА "А" ----

			ldi temp,0b11111110              ; бит 0 - вход АЦП (сетевое напряжение)
                                                ; бит 1-7 - незадействованы
			out DDRA,temp;
			ldi temp,0b00000000              ; включаем подтяжку для входов 
                                                ; и задаём начальные состояния выходов порта А
			out PORTA,temp;


               ;---- НАСТРОЙКА ПОРТА "В" ----

			ldi temp,0b11111111              ; пока не используем
			out DDRB,temp;
			ldi temp,0b00000000              ; включаем подтяжку для входов 
                                                ; и задаём начальные состояния выходов порта B
			out PORTB,temp;


               ;---- НАСТРОЙКА ПОРТА "С" ----
               ; ПОРТ "С" КОММУТИРУЕТ ОБМОТКИ ТРАНСОФРМАТОРА

			ldi temp,0b11111111               ; определяем входы и выходы порта C
			out DDRC,temp;
			ldi temp,0b00000000               ; включаем подтяжку для входов 
                                                 ; и задаём начальные состояния выходов порта C
			out PORTC,temp;


               ;---- НАСТРОЙКА ПОРТА "D" ----

			ldi temp,0b11110111               ; биты 0-2 порта D (выходы) отвечают
											  ; за динамическую индикацию, бит 3 (вход) 
											  ; определяет состояние кнопки
		    out DDRD,temp;
			ldi temp,0b11110111               ; включаем подтяжку для входов 
                                                 ; и задаём начальные состояния выходов порта D
			out PORTD,temp;


			;==== ЗАВЕРШЕНО ====                                 







			;==== КОНФИГУРИРОВАНИЕ МОДУЛЯ АЦП ====
			ldi temp,0b10001110               ; бит 7 - включаем АЦП (1)
                                                 ; бит 6 - не запускаем преобразование (0);
					                          ; бит 5 - непрерывный запуск АЦП (1) 
					                          ; бит 4 - флаг перывания АЦП (0)
					                          ; бит 3 - разрешение прерывания АЦП (1)
					                          ; биты 2-0 - выбор частоты преобразования (110) 110=СК/64

			out ADCSRA,temp                   ;
			ldi temp,0b11100000               ; биты 7,6 - внутренний ИОН 2,56В (11)
                                                 ; бит 5 - результат вырвнен влево (1) "деление на 4"
					                          ; биты 4-0 - выбор входного канала (00000) вход ADC0 (сетевое напряжение)
			out ADMUX,temp                    

			;==== ЗАВЕРШЕНО ====





		    ;==== КОНФИГУРИРОВАНИЕ  ТАЙМЕРА Т0 ====

			; ТАЙМЕР ИСПОЛЬЗЕТСЯ ДЛЯ ДИНАМИЧЕСКОЙ ИНДИКАЦИИ

			ldi temp,0b00000100               ; 101=СК/256
			out TCCR0,temp                    ; 
			ldi temp,0b00000010               ; разрешение перывания по совпадению
			out TIMSK,temp                    ; 
			ldi temp,10                       ; до этого стояло 87, необходимы правильно выставить частоту тактирвоания!!!!!!
			out OCR0,temp                     ;

			;==== ЗАВЕРШЕНО ====


			; ОПРЕДЕЛЕНИЕ КОНСТАНТ

			ldi numbersigment,3;
			ldi counterADC,1;
			ldi REG2,1;





               ;==== ЗАВЕРШЕНО ====




			; ==== КОДЫ СЕМИСЕГМЕНТНОГО ИНДИКАТОРА (НУЛЕВОЙ БИТ ПОРТА ЭТО "a") ==== 
kod:
			.db 0b00111111,0b00000110,0b01011011,0b01001111,0b01100110,0b01101101,0b01111101,0b00000111,0b01111111,0b01101111;
                                                ; сохринили коды сегментов индикатора в памяти программы 
			                                 ; для экономии регистров

			;==== ЗАВЕРШЕНО ====






			sei                              ; разрешаем все прерывания
			sbi ADCSRA,ADSC                  ; запуск АЦП




;==== НАЧАЛО ОСНОВНОГО ЦИКЛА ПРОГРАММЫ ====

Start:
			rcall button					; вызов подпрограммы обработки кнопки
			rjmp Start; 


;==== ЗАВЕРШЕНИЕ ОСНОВНОГО ЦИКЛА ПРОГРАММЫ ====




; ==== ПОДПРОГРАММА ОБРАБОТКИ КНОПКИ ====

button:							
			cli								; запрещаем прерывания
			ldi Delay1,0x40; примерно полсекунды задержка, выставить правильно тактовую частоту!!!!!
			ldi Delay2,0x01;

			sbic PinD,3;
			rjmp ON;

			reti								; в противном случае разрешаем прерывания и
											; выходим из подпрограммы

ON:
			inc REG2;

			sei;
			rcall Loop;


			reti;



											; разрешаем прерывания
Loop:
			subi Delay1,1;
			sbci Delay2,0;

			brcc Loop;
			ret				
; ==== КОНЕЦ ПОДПРОГРАММА ОБРАБОТКИ КНОПКИ ====






; ==== ПОДПРОГРАММА УПРАВЛЕНИЯ И ОБРАБОТКИ ПРЕРЫАНИЙ АЦП ====

Chenal:
			cli;
			push temp                   	 ; сохраняем в стеке рабочий регистр
			in temp,SREG               	     ; подготовка к сохранению регрситра состояний
			push temp                   	 ; сохранение регистра 
			cpi counterADC,1				 ; измеряли первый канал????
			breq in_voltage					 ; переход к обработке результатов измерения 1-го канала
			cpi counterADC,2				 ; измеряли второй канал????
			breq out_voltage1				 ; переход к обработке результатов измерения 2-го канала
			rjmp out_current				 ; переход к обработке результатов измерения 3-го канала


out_voltage1:
rjmp out_voltage;


; Обработка 1-го канала

in_voltage:

			inc counterADC					 ; увеличиваем счётчик АЦП на один
			;in result_in_volt,adch			 ; переносим результат АЦП в регистр хранения величины входного напряжения
			mov result,result_in_volt         ; пересылка результата преобразования АЦП в вспомогательный регистр
			cpi result,220                   ; 
			brlo Litle                       ; входное напряжение меньше 220
			breq Ravno                       ; входное напряжение равно 220
			rjmp Hight                       ; входное напряжение больше 220

; ### Цикд вступает в работу, елси входное напряжение меньше 220 Вольт ###
Litle:
			cpi result,210; 
			brpl M1                          ; напряжение  пределах 210-220
			cpi result,200; 
			brpl M2                          ; напряжение  пределах 200-210
			cpi result,190; 
			brpl M3                          ; напряжение  пределах 190-200
			cpi result,180; 
			brpl M4                          ; напряжение  пределах 180-190
			brmi M5                          ; меньше 180 Вольт (невозможно стабилизировать)


; ### Цикд вступает в работу, елси входное напряжение больше 220 Вольт ###
Hight:
			cpi result,230; 
			brmi M6                         ; напряжение  пределах 220-230
			cpi result,240; 
			brmi M7                         ; напряжение  пределах 230-240
			cpi result,250; 
			brmi M8                         ; напряжение  пределах 240-250
			cpi result,255; 
			brmi M9                         ; напряжение  пределах 250-260
			brpl M10                        ; больше 260 Вольт (невозможно стабилизировать)


; ### Цикд вступает в работу, елси входное напряжение равно 220 Вольт ###
Ravno:
			rjmp M11                        ; напряжение равно 220


; ===ЦИКЛЫ ОБРАБОТКИ НАПРЯЖЕНИЙ===

M1:                                             ; напряжение  пределах 210-220
			ldi temp,0b10011001			    ; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage;

M2:                                             ; напряжение  пределах 200-210
			ldi temp,0b10000001			    ; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage; 

M3:                                           	; напряжение  пределах 190-200
			ldi temp,0b10000000				; задаём конфигурацию обмоток
			out portC,temp					;
			rjmp exit_in_voltage			; 

M4:                                           	; напряжение  пределах 180-190
			ldi temp,0b00000000				; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage			; 

M5:                                           	; меньше 180 Вольт (невозможно стабилизировать)
			ldi temp,0b01000000				; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage;

M6:                                           	; напряжение  пределах 220-230
			ldi temp,0b00100000				; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage			; 

M7:                                           	; напряжение  пределах 230-240
			ldi temp,0b00010000				; задаём конфигурацию обмоток
			out portC,temp					;
			rjmp exit_in_voltage			;

M8:                                           	; напряжение  пределах 240-250
			ldi temp,0b00001000				; задаём конфигурацию обмоток
			out portC,temp					; 
			rjmp exit_in_voltage			; 

M9:                                          	; напряжение  пределах 250-260
			ldi temp,0b00000100				; задаём конфигурацию обмоток
			out portC,temp;
			rjmp exit_in_voltage			;

M10:                                        	; больше 260 Вольт (невозможно стабилизировать)
			ldi temp,0b00000010				; задаём конфигурацию обмоток
			out portC,temp					;
			rjmp exit_in_voltage			; 

M11:                                        	; напряжение равно 220
			ldi temp,0b00000001				; задаём конфигурацию обмоток
			out portC,temp					;
			rjmp exit_in_voltage			;



exit_in_voltage:
			ldi temp,0b10001110             ; бит 7 - включаем АЦП (1)
                                               ; бит 6 - не запускаем преобразование (0);
					                        ; бит 5 - непрерывный запуск АЦП (1) 
					                        ; бит 4 - флаг перывания АЦП (0)
					                        ; бит 3 - разрешение прерывания АЦП (1)
					                        ; биты 2-0 - выбор частоты преобразования (110) 110=СК/64

			out ADCSRA,temp                 ;
			ldi temp,0b11100000             ; биты 7,6 - внутренний ИОН 2,56 В (11)
                                               ; бит 5 - результат вырвнен влево (1) "деление на 4"

			ldi temp,0b11100001               ; биты 7,6 - внутренний ИОН 2,56В (11)
                                                 ; бит 5 - результат вырвнен влево (1) "деление на 4"
					                          ; биты 4-0 - выбор входного канала (00000) вход ADC0 (сетевое напряжение)
			out ADMUX,temp  
				sbi ADCSRA,ADSC;
			pop temp                   		; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              		; восстановление содеримого рабочего регистра
			pop temp                   		; восстановление содеримого рабочего регистра
			reti							;


out_voltage:
			inc counterADC					;
			;in result_out_volt,adch			;
			rjmp exit_out_voltage			;

exit_out_voltage:
			ldi temp,0b10001110             ; бит 7 - включаем АЦП (1)
                                               ; бит 6 - не запускаем преобразование (0);
					                        ; бит 5 - непрерывный запуск АЦП (1) 
					                        ; бит 4 - флаг перывания АЦП (0)
					                        ; бит 3 - разрешение прерывания АЦП (1)
					                        ; биты 2-0 - выбор частоты преобразования (110) 110=СК/64

			out ADCSRA,temp                 ;
			ldi temp,0b11100000             ; биты 7,6 - внутренний ИОН 2,56 В (11)
                                               ; бит 5 - результат вырвнен влево (1) "деление на 4"

			ldi temp,0b11100010               ; биты 7,6 - внутренний ИОН 2,56В (11)
                                                 ; бит 5 - результат вырвнен влево (1) "деление на 4"
					                          ; биты 4-0 - выбор входного канала (00000) вход ADC0 (сетевое напряжение)
			out ADMUX,temp  
			sbi ADCSRA,ADSC					;
			pop temp                   		; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              		; восстановление содеримого рабочего регистра
			pop temp                   		; восстановление содеримого рабочего регистра
			reti							;

out_current:

			ldi counterADC,1				;
			;in result_in_current,adch		;
			rjmp exit_in_current			;


exit_in_current:
			ldi temp,0b10001110             ; бит 7 - включаем АЦП (1)
                                               ; бит 6 - не запускаем преобразование (0);
					                        ; бит 5 - непрерывный запуск АЦП (1) 
					                        ; бит 4 - флаг перывания АЦП (0)
					                        ; бит 3 - разрешение прерывания АЦП (1)
					                        ; биты 2-0 - выбор частоты преобразования (110) 110=СК/64

			out ADCSRA,temp                 ;
			ldi temp,0b11100000             ; биты 7,6 - внутренний ИОН 2,56 В (11)
							;
			ldi temp,0b11100000               ; биты 7,6 - внутренний ИОН 2,56В (11)
                                                 ; бит 5 - результат вырвнен влево (1) "деление на 4"
					                          ; биты 4-0 - выбор входного канала (00000) вход ADC0 (сетевое напряжение)
			out ADMUX,temp  
			sbi ADCSRA,ADSC;	
			pop temp                   		; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              		; восстановление содеримого рабочего регистра
			pop temp                   		; восстановление содеримого рабочего регистра
			reti							;



; КОНЕЦ ПОДПРОГРАММА УПРАВЛЕНИЯ И ОБРАБОТКИ ПРЕРЫАНИЙ АЦП








Timer0: 
			cli								;	
			push temp                   	; сохраняем в стеке рабочий регистр
			in temp,SREG               	    ; подготовка к сохранению регрситра состояний
			push temp                   	; сохранение регистра 						
			cpi REG2,1						;
			breq Chenal_1					; переход на метку работы с результатом входного напряжения
			cpi REG2,2						;
			breq Chenal_2					; переход на метку работы с результатом выходного напряжения
			cpi REG2,3						;
			breq Chenal_3					; переход на метку работы с результатом выходного тока
			rjmp Chenal_1					; переход на метку работы с результатом входного напряжения

Chenal_1:
			mov result,result_in_volt		;
			rjmp Indicators					;

Chenal_2:
			mov result,result_out_volt		;
			rjmp Indicators					;

Chenal_3:
			mov result,result_in_current		;
			rjmp Indicators					;

Chenal_End:
ldi Reg2,1;
mov indication_out,result_in_volt;
rjmp Indicators;






Indicators:


			mov indication_out,result;
			rcall DigitalConverter;


			rjmp Indication;





;==== ПОДПРОГРАММА ПЕРЕВОДА ДВОИЧНЫХ ЧИСЕЛ В ДЕСЯТИЧНЫЕ  ====

DigitalConverter:
			clr temp                   ; очищаем рабочий регистр
			out TCNT0,temp             ; сбрасываем счётчик
			clr temp                   ; очситка рабочего регистра

			mov Hundreds,temp          ; очистка вспомогательного регистра сотен
			mov Tens,temp              ; очистка вспомогательного регистра десятков
			mov Ones,temp              ; очистка вспомогательного регистра единиц

; Обработка сотен
FindHundreds: 
			subi indication_out,100                ; вычитаем из результата 100
			brcs FindTens              ; переходим к обработке дестков, если флаг переноса установлен
			inc temp                   ; если флаг переноса сброшен, увеличить количество сотен на единицу
			mov Hundreds,temp          ; пересылаем содержимое в регистр Hundreds, отвечающий за сотни
			rjmp FindHundreds          ; вновь возвращаемся к вычитанию сотен

; Обработка десятков
FindTens:
			clr temp                   ; очищаем рабочий регистр
			subi indication_out,-100               ; прибавляем к оставшемуся результату 100
			subi indication_out,10                 ; вычитаем из результата 10
			brcs FindOnes              ; переходим к обработке единиц, если флаг переноса установлен
			inc temp                   ; если флаг переноса сброшен, увеличить количество десятков на единицу
			mov Tens,temp              ; пересылаем содержимое в регистр Tens, отвечающий за десятки
			rjmp FindTens+2            ; вновь возвращаемся к вычитанию десятков

; Обработка единиц
FindOnes:
			subi indication_out,-10                ; прибавляем к оставшемуся результату 10
			mov Ones,indication_out                ; пересылаем содержимое в регистр Ones, отвечающий за единицы
ret;
;==== КОНЕЦ ПОДПРОГРАММЫ ПЕРЕВОДА ДВОИЧНЫХ ЧИСЕЛ В ДЕСЯТИЧНЫЕ  ====







;==== ПОДПРОГРАММА ВЫБОРА СЕМИСЕГМЕНТНОГО ИНДИКАТОРА  ====

Indication:
TC0:
			clr temp                   ; очищаем рабочий регистр
			out TCNT0,temp             ; сбрасываем счётчик
			in temp,PinD;
			andi temp,0b11111000;
			ori temp,0b00000111;

			out PortD,temp             ; тушим все индикаторы
			cpi numbersigment,3        ; проверяем какой семисегментный индиктаор работал в предыдущий раз
			breq Three                 ; если работал первый индиктаор, то возвращаемся к третьему
			cpi numbersigment,2        ; проверяем какой семисегментный индиктаор работал в предыдущий раз
			breq Too                   ; если работал третий индиктаор, то возвращаемся ко второму
			cpi numbersigment,1        ; проверяем какой семисегментный индиктаор работал в предыдущий раз
			breq One                   ; если работал второй индиктаор, то возвращаемся к первому

;--- Обрабаотка первого семисегмента индикатора ---
One:
			in temp,PinD;
			andi temp,0b11111000
			ori temp,0b00000011

			out portD,temp             ; включаем первый семисегментный индикатор
			mov temp,Ones              ;
			rcall Display              ; вызываем подпрограмму отображения числа на первом индикаторе
			ldi numbersigment,3        ; при следующем генерирование прерывания начнётся обработка третьего сегмента
			pop temp                   ; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              ; восстановление содержимого регистра состояния
			pop temp                   ; восстановление содеримого рабочего регистра
			reti                       ; выход из программы обрабаотки прерывания

;--- Обрабаотка второго семисегмента индикатора ---
Too:

			in temp,PinD;
			andi temp,0b11111000
			ori temp,0b00000101


			out portD,temp             ; включаем второй семисегментный индикатор
			mov temp,Tens              ;
			rcall Display              ; вызываем подпрограмму отображения числа на первом индикаторе
			dec numbersigment          ; при следующем генерирование прерывания начнётся обработка первого сегмента
			pop temp                   ; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              ; восстановление содеримого рабочего регистра
			pop temp                   ; восстановление содеримого рабочего регистра
			reti                       ; выход из программы обрабаотки прерывания

;--- Обрабаотка третьего семисегмента индикатора ---
Three:
			in temp,PinD;
			andi temp,0b11111000
			ori temp,0b00000110

			out portD,temp             ; включаем третий семисегментный индикатор
			mov temp,Hundreds          ;
			rcall Display              ; вызываем подпрограмму отображения числа на первом индикаторе
			dec numbersigment          ; при следующем генерирование прерывания начнётся обработка второго сегмента
			pop temp                   ; подготовка к восстановлению содержимого регистра состояния
			out SREG,temp              ; восстановление содеримого рабочего регистра
			pop temp                   ; восстановление содеримого рабочего регистра
			reti                       ; выход из программы обрабаотки прерывания


;==== КОНЕЦ ПОДПРОГРАММЫ ВЫБОРА СЕМИСЕГМЕНТНОГО ИНДИКАТОРА  ====









;==== ПОДПРОГРАММА ВЫВОДА ИНФОРМАЦИИ НА СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР  ====

; для вывода числа необходимо в регистр "temp" поместить десятичное число в двоичной форме

Display:
			ldi ZH,High(kod*2)         ;
			ldi ZL,Low(kod*2)          ;
			add ZL,temp                ; в регистре temp располагается число которое далее выводится на дисплей
			lpm						   ;
			mov temp,R0           ; код семисегмента оправляется в регистр R0
			out PortB,temp             ; вывод числа на индикатор
			ret                        ; выход из подпрограммы

;==== КОНЕЦ ПОДПРОГРАММЫ ВЫВОДА ИНФОРМАЦИИ НА СЕМИСЕГМЕНТНЫЙ ИНДИКАТОР  ====

Изменено пользователем Vitaliy129
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

  • Ответов
  • Создана
  • Последний ответ

Топ авторов темы

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Программу переписывал много раз, в одном месте переход немножко не туда поставил, как обычно получилось: думал правильно, а написал не ту метку. Как только исправил всё заработало.

Ссылка на комментарий
Поделиться на другие сайты

  • 2 недели спустя...

Учусь программировать мк AVR на Си. Сделал маяк, мигалку, бегущий огонь. Поработал с кнопками.

Теперь появился такой вопрос: есть 8 светодиодов, подключенных к выводам PD0-PD7 микроконтроллера. Светодиоды просто мигают.

Необходимо реализовать следующее:

1. При нажатии кнопки, которая подключена к выводу PC0, остановить цикл while (1) в любом месте работы программы.

2. При этом должны загореться все 8 светодиодов.

3. При отпускании кнопки цикл while (1) продолжает свою работу.

Ссылка на комментарий
Поделиться на другие сайты

...
while(1)
{
...
while(!(PINC&(1<<PC0)){PORTD=0xFF;_delay_ms(50);/*антидребезг*/}
...
}
...

Изменено пользователем Goodefine

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

Ссылка на комментарий
Поделиться на другие сайты

...

while(1)

{

...

while(!(PORTC&(1<<PC0)){PORTD=0xFF;_delay_ms(50);/*антидребезг*/}

...

}

...

Дописал в код. CVAVR ругается на РС0 - заменил на PORTC.0, скомпилировал прошивку.

Моделирую в протеусе - при нажатии на кнопку основной цикл продолжается, т.е. ничего не протсходит.

PS: PC0 сконфигурирован как вход через подтягивающий резистор.

Ссылка на комментарий
Поделиться на другие сайты

Ещё такой вопрос, как сделать повторение операции несколько раз.

Например, поочередно зажигается светодиод от 0 к 7 биту, потом светодиод бежит в обратную сторону, затем все светодиоды мигают и т.д. Как сделать. чтобы светодиод бежал от 0 к 7 биту, допустим 3 раза, затем 3 раза в обратную сторону, потом 3 раза мигал.

Вот кусок кода:

void main(void)

{

int i;

char led[]={

0b00000001,

0b00000010,

0b00000100,

0b00001000,

0b00010000,

0b00100000,

0b01000000,

0b10000000,

0b01000000,

0b00100000,

0b00010000,

0b00001000,

0b00000100,

0b00000010,

0b00000001};

...

while (1)

{

for(i=0;i<15;i++)

{

PORTD=led;

sleep;

}

}

}

В этом коде светодиод бежит в одну сторону один раз, и в другую один раз, затем цикл повторяется.

Нужно чтобы он бежал в одну сторону 3 раза, затем в другую 3 раза и т.д.

Ссылка на комментарий
Поделиться на другие сайты

  • 2 недели спустя...

Здравствуйте, заранее извеняюсь если подобный вопрос был, но поиском не нашел ничего =( Вообщем интересует, как разбить программу на несколько исходных файлов (MPLab PIC12/16), чтобы можно было задержки вынести в один файл, а основной цикл и инициализация допустим в другом были. А при компиляции они соединялись и прошивались в контроллер? (програмлю на ассемблере)

Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...

Как программировать кнопку, подключенную на порт ввода/вывода МК, чтобы по нажатию на него переключалось режим работы ус-ва?

Например:

нажали - режим 1

еще раз нажали - режим 2

еще раз нажали - выкл

Ссылка на комментарий
Поделиться на другие сайты

@Rinatus, по нажатию кнопки инкрименируем счетчик до трех, режим работы задается в зависимости от числа в счетчике. Не забываем про антидребезг при обработке.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

Для этого надо хранить в памяти предыдущее состояние кнопки. При проверке состояния кнопки, если предыдущее = "отжато" а текущее = "нажато" инкрементируем счетчик, сравниваем его с "3" если больше или равно - обнуляем счетчик. копируем текущее состояние кнопки в предыдущее.

Выполняя эту процедуру с интервалом порядка 5..10мс получишь желаемое.

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

Есть обработчик прерывания на МК AVR, который проверяет состояние кнопки и в зависимости от состояния кнопки переходит в определенный адрес.

Как сделать выход из прерывания? Если использовать команду reti, программа возвращается туда, где была прервана. А мне нужно, чтобы программа возвращалась на другой адрес.

Ссылка на комментарий
Поделиться на другие сайты

А зачем тебе возвращаться на другой адрес ИЗ ПРЕРЫВАНИЯ? Посмотри лучше даташит насчет работы прерываний...

Прерывание может возникнуть в ЛЮБОМ месте программы, и чтобы чего не вышло, нужно непременно возвратить управление ровно в ту точку где это прерывание возникло, иначе это может вызвать неадекватное поведение программы. И по этой же причине обработчик прерывания не должен изменять регистр статуса и выполнятся максимально быстро, т.е. выполнять как можно меньше действий.

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

Есть обработчик прерывания на МК AVR, который проверяет состояние кнопки и в зависимости от состояния кнопки переходит в определенный адрес.

Как сделать выход из прерывания? Если использовать команду reti, программа возвращается туда, где была прервана. А мне нужно, чтобы программа возвращалась на другой адрес.

Кто вас научил этому изуверскому способу?

Нет, если хотите, можете и так сделать. Только не забудьте после перехода надлежащим образом восстановить стек (убрать из него переменные прерывания, регистр флагов, адрес возврата), может ещё что. Т.е. все те вещи, которые обычно делаются компилятором (если, конечно, не на асме пишете).

А вообще - по-нормальному это делается совершенно иначе и гораздо проще:

- объявляете глобальную переменную - флаг (признак) нажатой кнопки. Если пишете на Си, то объявлять с модификатором volatile: char volatile keyFlag=0;

- в обработчике, когда поймали нажатую кнопку, делаете keyFlag=1;

- в главной программе (или где Вам надо) пишете:

if (keyFlag==1)
{
..............

// сбрасываем флаг
keyFlag=0;
} // if

И всё, без разных извратов ....

Ссылка на комментарий
Поделиться на другие сайты

Да хоть и на Асме, указываем вектор прерывания со ссылкой на метку обработчика, в конце обработчика reti, все остальное делается аппаратно. Ну и сохраняем в начале и востанавливаем в конце в обработчике необходимые константы, которые может модифицировать обработчик.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

Для этого надо хранить в памяти предыдущее состояние кнопки. При проверке состояния кнопки, если предыдущее = "отжато" а текущее = "нажато"
а прерывания по фронту недоступны?
Если использовать команду reti, программа возвращается туда, где была прервана. А мне нужно, чтобы программа возвращалась на другой адрес.
В свое время делал модель многозадачной операционной системы на AVR'е. Тоже была проблема что по таймеру нужно возвращаться не туда откуда был вызван.

TIMER0_OVF:
in lSREG, SREG   // сохраняем значения флагов
// некий код переключения процессов
out SREG,nSREG   // и записываем новое уже для другого процесса
pop laddr1   // сохраняем предыдущий адрес возврата
pop laddr2   // он 2-байтный
push naddr2  // и записываем следующий
push naddr2  // также 2-байтный
reti
// lSREG, nSREG, laddr1, laddr2, naddr1, naddr2 - в данном случае регистры. В реальности лучше писать в память или стек, но для примера сойдет

Как-то так

Изменено пользователем COKPOWEHEU

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

а прерывания по фронту недоступны?
А что будем делать с дребезгом? Он выдаст с десяток фронтов и они все будут обработаны прерыванием... надо будет как-то городить подавитель дребезга программный, аппаратный ли - это все лишнее.

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

А что будем делать с дребезгом?
Опять же как я делал: прерывание обрабатывается, запрещает себя и запускает таймер. По прерыванию таймера разрешается прерывание по фронту и таймер останавливается. Это если есть лишние таймеры; если нет, но есть время можно и задержку в прерывании поставить. Ну или аппаратная RC-цепочка, не так много места она занимает.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Играться с запретом прерываний, что-то добавлять в схему, когда можно отлично обойтись без этого всего.

Учение - изучение правил. Опыт - изучение исключений.

Ссылка на комментарий
Поделиться на другие сайты

Если есть "лишний" таймер, то лучше сделать на нём периодические вызовы обработки состояний кнопок, следить за изменениями этих состояний и устанавливать флаги. Можно и счётчики туда прикрутить для получении времени нажатия кнопки.

Прикручивание кнопок на внешние прерывания - идиотизм, геморрой и лишние затраты ресурсов МК.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...