Как ни странно, возникла необходимость считать ID из DS1990 Я сделал маленький макет ридера, который читает «таблетку» и передаёт по UART-у ASCII кодом (4800 бод 8N1). Вот маленькая схемка макета.
Ниже привожу текст прошивки переходника.
;* ************************************************************************ * ;* ib2uart.avr, iButton-reader * ;* ************************************************************************ * .include "tn13def.inc" ; опции программирования ; BODLEVEL1=BODLEVEL0=SUT0=CKSEL0=0 .set VERSION = 0x0100 ; * описание портов контроллера * ; выходной интерфейс управления реле/ключом .equ CTBout = PORTB ; выходной порт .equ CTBcfg = DDRB ; порт конфигурации выходов .equ CTBin = PINB ; порт конфигурации выходов .equ ledpin = 0 ; LED .equ ibpin = 1 ; ib-вход/выход .equ ouart = 4 ; UART-выход .equ CTB_CFG = (1<<ouart)|(1<<ledpin)|(0<<ibpin) ; константа cfg порта .equ CTB_OUT = (1<<ouart)|(1<<ledpin)|(0<<ibpin) ; константа out порта ; тактовая частота МГц #define XCLK 9.6 .equ CN2MKS = INT((2*XCLK-7)/3) ; константа 2мкс .equ CN5MKS = INT((5*XCLK-9)/3) ; константа 5мкс .equ CN10MKS = INT((10*XCLK-9)/3) ; константа 10мкс .equ CN50MKS = INT((50*XCLK-9)/3) ; константа 50мкс ; * назначение переменных * .def cnt = R19 .def tmp1 = R20 ; переменная общего пользования .def tmp2 = R21 ; переменная общего пользования .def tmp3 = R22 ; переменная общего пользования .def tmp4 = R23 ; переменная общего пользования .equ store = SRAM_START ; указатель на память ; кодовый сегмент .cseg ; CODE segment ;______________________________________________________________ ; таблица .org 0 rjmp main_rstcold ; вектор сброса .org INT0addr reti ; External Interrupt 0 .org PCI0addr reti ; External Interrupt Request 0 .org OVF0addr reti ; Timer/Counter0 Overflow .org ERDYaddr reti ; EEPROM Ready .org ACIaddr reti ; Analog Comparator .org OC0Aaddr reti ; Timer/Counter0 Compare Match 0A .org OC0Baddr reti ; Timer/Counter Compare Match B .org WDTaddr reti ; Watchdog Time-out .org ADCCaddr reti ; ADC Conversion Complete ;______________________________________________________________ uart_del: ; полубитная задержка ldi tmp3,251 ; загрузка счетчика задержки uart_dlp: nop ; пустой такт dec tmp3 ; декремент счётчика задержки brne uart_dlp ; закрытие цикла ожидания ret ; выход ;______________________________________________________________ pr_hex: push tmp1 ; swap tmp1 ; rcall pr_dig ; pop tmp1 ; pr_dig: andi tmp1,0x0F ; cpi tmp1,0x0A ; ldi tmp2,0x30 ; brcs prhx_coring ; ldi tmp2,0x37 ; prhx_coring: add tmp1,tmp2 ; ;______________________________________________________________ putchar: ; функция передачи байта TxByte ; IN - tmp1 ; OUT - нет ; CHG - нет push tmp1 ; push tmp2 ; push tmp3 ; ldi tmp2,1+8+1 ; 1+8+1 com tmp1 ; sec ; установка старт-бита putc_pblm: brcc putc_psbm ; переход на установку лог.1, если C==0 cbi CTBout,ouart ; установка лог.0 rjmp putc_pbdm ; переход к битовой задержке putc_psbm: sbi CTBout,ouart ; установка лог.1 nop ; тактовое уравнивание putc_pbdm: rcall uart_del ; rcall uart_del ; lsr tmp1 ; получение в C след.бита dec tmp2 ; декремент счетчика битов brne putc_pblm ; проверка закрытия цикла посылки битов pop tmp3 ; pop tmp2 ; pop tmp1 ; ret ; выход ;______________________________________________________________ ; вектор сброса, вход в основную петлю программы main_rstcold: ; инициализация сторожевого таймера cli ; запрет всех прерываний ; установка стека ldi tmp1,low(RAMEND); загрузка указателя стека out SPL,tmp1 ; запись указателя ; начальная установка конфигурации порта B ; PB5 PB4 PB3 PB2 PB1 PB0 ; LED RSL RSH ; in in in out out out ldi tmp1,CTB_OUT ; значение выходов порта out CTBout,tmp1 ; запись состояния выходов в порт ldi tmp1,CTB_CFG ; значение выходов порта B out CTBcfg,tmp1 ; запись I/O конфигурации ; разрешаем внешние прерывания по фронту/срезу ldi tmp1,(1<<ISC00) ; значение для int0 по фронту/срезу out MCUCR,tmp1 ; запись в регистр ldi tmp1,(0<<INT0) ; значение для разрешения int0 out GIMSK,tmp1 ; разрешение прерываний int0 sei ; разрешение всех прерываний main_loop: rcall ib_reset ; сброс i-button brts main_present ; переход, если i-button ответил rjmp main_loop ; зацикливание main_present: ldi tmp1,0x33 ; код команды чтения ID DS1990 rcall ib_write ; передача команды в i-button ldi ZL,low(store) ; мл.байта указателя на массив, куда будет запоминаться ID ldi ZH,high(store) ; ст.байта указателя на массив, куда будет запоминаться ID ldi tmp4,0x08 ; кол-во байт ID main_rdlp: push tmp4 ; сохраняем счётчик rcall ib_read ; читаем данные из i-button pop tmp4 ; восстанавливаем счётчик байтов push tmp4 ; опять сохраняем счётчик cpi tmp4,8 ; проверяем, 1й ли байт считан brne main_famskp ; переход, если не 1й cpi tmp1,0x00 ; значение 1го байта ==0? brne main_famskp ; если !=0, то продолжаем чтение (считан тип ИМС) rjmp main_loop ; если ==0, то это просто замкнули контакты main_famskp: st Z+,tmp1 ; запоминаем байт в памяти pop tmp4 ; восстанавливаем счётчик байтов dec tmp4 ; декремент счётчика brne main_rdlp ; закрываем цикл чтения ID ; проверка CRC ldi ZL,low(store) ; мл.байта указателя на массив ID ldi ZH,high(store) ; ст.байта указателя на массив ID clr tmp2 ; сброс начального значения CRC ldi tmp4,0x07 ; кол-во байт, по которым считается CRC main_crclp: ld tmp1,Z+ ; загружаем очередной байт rcall update_crc ; вычисляем очередное значение CRC dec tmp4 ; декрементируем счётчик байтов brne main_crclp ; закрытие цикла подсчёта CRC ld tmp1,Z ; загружаем CRC, которое считано из i-button eor tmp1,tmp2 ; сравниваем с CRC, которое вычислили сами breq main_crcok ; переход, если CRC совпали rjmp main_loop ; если ошибка CRC - возвращаемся в основную петлю main_crcok: ldi ZL,low(store) ; мл.байта указателя на массив ID ldi ZH,high(store) ; ст.байта указателя на массив ID ldi tmp4,0x08 ; установка кол-ва байтов, которые будут переданы по UART cli ; запрет прерываний main_txlp: push tmp4 ; сохранение счётчика ld tmp1,Z+ ; загрузка очередного байта ID из памяти rcall pr_hex ; вывод байта по UART ldi tmp1,0x20 ; установка кода пробела rcall putchar ; вывод символа по UART pop tmp4 ; восстановление счётчика dec tmp4 ; декремент brne main_txlp ; закрытие петли передачи ID ldi tmp1,0x0D ; установка кода "\r" rcall putchar ; вывод символа по UART ldi tmp1,0x0A ; установка кода "\n" rcall putchar ; вывод символа по UART sei ; разрешение прерываний cbi CTBout,ledpin ; включение светодиода ldi tmp3,0x02 ; установка ст.байта задержки ledp_lph: clr tmp2 ;~1, установка "среднего" байта задержки ledp_lpm: clr tmp1 ;~1, установка "младшего" байта задержки ledp_lpl: nop ;~1, пустые такты, чтобы задержка тянулась медленнее :) nop ; dec tmp1 ;~1, декремент мл.счётчика задержки brne ledp_lpl ;~2/1, закрытие мл.цикла dec tmp2 ;~1, декремент ср.счётчика задержки brne ledp_lpm ;~2/1, закрытие ср.цикла dec tmp3 ;~1, декремент ст.счётчика задержки brne ledp_lph ;~2/1, закрытие ст.цикла sbi CTBout,ledpin ; выключение светодиода rjmp main_loop ; возврат в основную петлю ;______________________________________________________________ ; задержка 50мкс, 3(rcall)+2(rjmp) + 3*n+4(ret) del50mks: ldi tmp4,CN50MKS ;~1, установка константы 50мкс rjmp del2_lp ;~2, переход на петлю задержки ;______________________________________________________________ ; задержка 10мкс, 3(rcall)+2(rjmp) + 3*n+4(ret) del10mks: ldi tmp4,CN10MKS ;~1, установка константы 10мкс rjmp del2_lp ;~2, переход на петлю задержки ;______________________________________________________________ ; задержка 5мкс, 3(rcall)+2(rjmp) + 3*n+4(ret) del5mks: ldi tmp4,CN5MKS ;~1, установка константы 5мкс rjmp del2_lp ;~2, переход на петлю задержки ;______________________________________________________________ ; задержка 2мкс, 3(rcall)+2(rjmp) + 3*n+4(ret) del2mks: ldi tmp4,CN2MKS ;~1, установка константы 5мкс del2_lp: dec tmp4 ;~1, декремент счётчика задержки brne del2_lp ;~2/1, закрытие цикла ret ;~4, выход ;______________________________________________________________ ; задержка 90мкс del90mks: rcall del10mks ; 10mks rcall del10mks ; 10mks rcall del10mks ; 10mks rcall del10mks ; 10mks rjmp del50mks ; 50mks ;______________________________________________________________ ; задержка 100мкс del100mks: rcall del50mks ; 50mks rjmp del50mks ; 50mks ;______________________________________________________________ ; задержка 500мкс del500mks: rcall del100mks ; 100mks rcall del100mks ; 100mks rcall del100mks ; 100mks rcall del100mks ; 100mks rjmp del100mks ; 100mks ;______________________________________________________________ ; чтение/запись байта в i-button; запись 0xFF - это чтение ; из i-button, таймслоты те же ib_read: ldi tmp1,0xFF ; установка константы для чтения ib_write: mov tmp2,tmp1 ; установка параметра (здесь tmp2 рабочий регистр) ldi tmp3,8 ; установка счётчика битов rwloop: sbi CTBcfg,ibpin ; опускаем линию i-button в 0 rcall del2mks ; маленькая задержка 2мкс ror tmp2 ; бит, который будем передавать толкаем в C brcc wrzero ; если бит ==0, то оставляем линию i-button ==0 cbi CTBcfg,ibpin ; если бит ==0, то переводим линию i-button ==1 wrzero: rcall del10mks ; маленькая задержка, чтобы вывод перешёл в 1 clc ; в C будет значение бита, посланного i-button sbic CTBin,ibpin ; читаем значение вывода i-button sec ; устанавливаем C==1, если вывод i-button==1 ror tmp1 ; записываем считанное значение в tmp1 rcall del50mks ; выдерживаем до конца время тайм-слота cbi CTBcfg,ibpin ; поднимаем (отпускаем) линию i-button: rcall del2mks ; маленькая задержка 2мкс, чтобы линия поднялась dec tmp3 ; декремент счётчика битов brne rwloop ; закрытие цикла чтения 8ми битов ret ; выход ;______________________________________________________________ ; сброс i-button и чтение импульса "присутствия" i-button на линии, ; результат возвращается в T ib_reset: sbi CTBcfg,ibpin ; линия i-button ==0 rcall del500mks ; большая задержка: i-button обесточивается cbi CTBcfg,ibpin ; поднимаем линию i-button rcall del90mks ; ждём заряда внутреннего конденсатора i-button clt ; сброс T sbis CTBin,ibpin ; проверяем состояние линии: если i-button присутствует, ; то он в этот момент должен удерживать линию в 0 set ; если линия удерживается в 0, то T==1, i-button на линии rcall del500mks ; ждём пока i-button отпустит линию ret ; выход ;______________________________________________________________ ; подсчёт байта CRC ; в tmp1 байт, который надо добавить в CRC, в tmp2 уже накопленный CRC8 ; алгоритм списан из спецификации на DS1990 update_crc: push tmp3 ; push tmp4 ; ldi tmp4,8 ; upcr_lp: mov tmp3,tmp2 ; eor tmp3,tmp1 ; sbrs tmp3,0 ; rjmp upcr_zbit ; ldi tmp3,0x18 ; eor tmp2,tmp3 ; lsr tmp2 ; sbr tmp2,(1<<7) ; rjmp upcr_shift ; upcr_zbit: lsr tmp2 ; upcr_shift: lsr tmp1 ; dec tmp4 ; brne upcr_lp ; pop tmp4 ; pop tmp3 ; ret ; выход