Задача
Измерять напряжение 0…5 В и показывать его с точностью до десятых.
Микроконтроллер: ATmega8, кварц 4 МГц. Среда: Atmel Studio / avra (или avra / Atmel Studio). Как настроить среду и прошить контроллер — в статье программирование AVR.
Что понадобится
- ATmega8
- кварц 8 МГц + 2×22 пФ
- два индикатора
- 7 резисторов 330 Ом
- 2 транзисторных ключа
- делитель на входе при измерении выше 5 В
Схема подключения
| Вывод | Подключение |
|---|---|
| PC0 / ADC0 | измеряемое напряжение (не выше 5 В) |
| PB0…PB6 | сегменты, PB7 — десятичная точка |
| PD0 / PD1 | разряды |
Алгоритм
- Измерить напряжение и получить код 0…255.
- Вычитать по 51 единице — столько приходится на один вольт.
- Остаток разложить на десятые доли шагами по 5 единиц.
- Вывести оба разряда, зажигая точку у целых.
Листинг на ассемблере
Код проверен ассемблером и собирается без ошибок. Скачать: a28.asm · a28.hex (готовая прошивка).
;=======================================================
; Проект 28. Цифровой вольтметр 0..5 В
; ATmega8, 8 МГц. Вход ADC0 (PC0)
; Индикация: целые вольты и десятые на двух разрядах
; Сегменты PB0..PB6 (PB7 — точка), разряды PD0/PD1
;=======================================================
.include "m8def.inc"
.def temp = r16
.def volts = r17
.def tenth = r18
.def acc = r19
.def loops = r20
.def d1 = r21
.def d2 = r22
.cseg
.org 0x0000
rjmp RESET
SEGTAB: .db 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110
.db 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111
RESET:
ldi temp, low(RAMEND)
out SPL, temp
ldi temp, high(RAMEND)
out SPH, temp
ldi temp, 0xFF
out DDRB, temp
ldi temp, 0x03
out DDRD, temp
cbi DDRC, PC0
ldi temp, (1<<REFS0)|(1<<ADLAR)
out ADMUX, temp
ldi temp, (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)
out ADCSRA, temp
MAIN:
rcall ADC_READ
mov acc, temp
rcall CONVERT
ldi loops, 50
SHOW:
cbi PORTD, PD1
mov temp, volts
rcall SEG
ori temp, 0b10000000 ; точка после целых вольт
out PORTB, temp
sbi PORTD, PD0
rcall DELAY5MS
cbi PORTD, PD0
mov temp, tenth
rcall SEG
out PORTB, temp
sbi PORTD, PD1
rcall DELAY5MS
dec loops
brne SHOW
rjmp MAIN
;--- код 0..255 -> вольты и десятые (51 единица на вольт) ---
CONVERT:
clr volts
mov temp, acc
V_LOOP: cpi temp, 51
brlo T_PART
subi temp, 51
inc volts
rjmp V_LOOP
T_PART:
clr tenth
T_LOOP: cpi temp, 5
brlo C_END
subi temp, 5
inc tenth
cpi tenth, 10
brne T_LOOP
clr tenth
rjmp T_LOOP
C_END: ret
ADC_READ:
in temp, ADCSRA
ori temp, (1<<ADSC)
out ADCSRA, temp
AD_W: in temp, ADCSRA
sbrc temp, ADSC
rjmp AD_W
in temp, ADCH
ret
SEG:
ldi ZL, low(SEGTAB<<1)
ldi ZH, high(SEGTAB<<1)
add ZL, temp
clr temp
adc ZH, temp
lpm temp, Z
ret
DELAY5MS:
ldi d2, 52
I2: ldi d1, 255
I1: dec d1
brne I1
dec d2
brne I2
ret
Пояснения
- Перевод сделан циклом вычитания командой
subi— приём универсален для любого масштабирования при отсутствии деления. - Точность ограничена восемью битами: шаг составляет около 20 мВ. Для большей точности читают все десять бит и стабилизируют опорное напряжение.
- Для напряжений выше 5 В ставят резистивный делитель, а коэффициент учитывают в пересчёте.
Что дальше
Разобравшись с этим проектом, переходите к следующему в разделе проекты на PIC. Справочник по архитектуре и периферии контроллеров — на странице микроконтроллеры AVR.