GUM

Members
  • Публикации

    7
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

О GUM

  • Звание
    Новенький

Информация

  • Город
    Тюмень

Электроника

  • Стаж в электронике
    Менее года
  • Сфера радиоэлектроники
    Микроконтроллеры
  1. Проблема с TWI(I2C)

    И так друзья) спасибо всем откликнувшимся :-D спустя 2 недели мучений, ковыряний протеуса, осмотра всех режимов отладки, все пошаговые и не пошаговые, я следил за состоянием всех регистров, как TWI , так и РОН, снижал частоту процессора, что только не делал. Заметил, что пока PC крутиться в главном цикле, который зациклен на main, rjmp main, т.е. он ничего не делает, регистр TWDR самостоятельно меняется на 00, а при передаче второго, третьего и тд байтов на FF не заходя в прерывание, и понял, что что-то тут не так! Уже хотел писать код без прерываний, так сказать быдло код, но решил проверить на микросхеме eeprom, о чудо, все работает, передает нужные байты. Тут надо сказать: Братан, а чего ты раньше не пробовал другие микрухи, а яв от пробовал! Т.к. схема связана с часами, то решил заменить на аналог DSхххх не помню точное название и там была та же самая хрень, только вместо первого байта 00 и последующий ff, он передавал немного другие, например первый 0x02, второй и последующие 0x55 , а я программировал на передачу только 0x01. Ясно, микруха фигово реализована в протеусе. Но все же она мне нужна, моя заказанная еще не пришла, стал копать , что же не так? Пробежался по даташиту, не нашел ничего специфического. Решил передавать байты в разные ячейки, скажем 10 раз по 3 байта каждый раз и того 30 ячеек проверю. И наконец-то обнаружил суть проблемы, по неизвестным причинам при первой отправке байта(ов), не важно, отправлять 1 байт или 1000000, возникает моя проблема , первый байт всегда 0х00, а второй и последующие(хоть миллион байтов) 0хff. А при последующей отправке во второй, третий и тд, все работает, как "часы". Может кто столкнулся с такой проблемой, надеюсь помогу кому в будущем) Тему можно закрывать!
  2. Проблема с TWI(I2C)

    Новая информация! Запустил отладчик в протеусе конкретно TWI, ошибка следующая, При отправке любого байта сначала пишется строчка [AVR TWI] Initiating data write 0xA2 [U3](я так понял это то, что я отправил в регистр TWDR), затем идет строчка [AVR TWI] Actual data read written 0xA2 [U3] (это то, что отправили слейву в данном случае). После отправки адреса ячейки для записи у меня одна песня играет, сначала идет строчка PC=0x00F2. [AVR TWI] Initiating data write 0x01 [U3], затем PC=0x0210. [AVR TWI] Actual data read written 0x00 [U3] (так записывает первый байт) последующие отправляет одинаково но по другому в отличие только от первого: PC=0x00F2. [AVR TWI] Initiating data write 0x01 [U3], PC=0x0210. [AVR TWI] Actual data read written 0xFF [U3] -второй байт(должен быть 0x01), PC=0x00F2. [AVR TWI] Initiating data write 0x01 [U3], PC=0x0210. [AVR TWI] Actual data read written 0xFF [U3] - третий, такой же четвертый и тд. То есть в регистр записываются нормальные значения, а по итогу отправляет совсем не те байты! Моет кому помогло понять, в чем ошибка... А то уже всю голову сломал! Брал тупо код обработчика прерываний на асме с сайта изиэлектроник, заменив там только макросы, ошибка идентичная! оставил там только свой макрос на отправку.
  3. Проблема с TWI(I2C)

    Всем привет! Начал разбираться с протоколом TWI(I2C) на авр, а именно atmega 8. Почитал статьи на изиэлектроник, написал обработку на прерываниях(подсматривая в пример), чтобы вникнуть. Начал тестить в протеус иии... Неизвестная бага не дает мне покоя. Старт производит, адрес слэйва передает(с битом на запись), адрес нужной ячейки передает, а уже при записи пишет ерунду, все время одно и то же, первый 0x00, второй 0xff, потом стоп(стоп запланирован) и какие бы байты я не писал в обработчике, передает 2 одинаковых 00 и ff... Ошибок не выдает, я поставил флаг на ошибки(1 на ноге), в нужное подпрерывание попадает ровно столько раз, сколько надо(тое ставил флаги туда), да и ставил флаги в другие обработчики прерываний(в которые не надо попадать в данном случае), но все норм. Я скину сюда часть кода, эквиваленты, озу нужные, макрос на отправку, и обработчики прерываний, которые используются для отправки байтов. Пишите, если нужна будет доп информация. Кстати, все прогнал по трассировщику в студии, просто сделал rcall на нужную последовательность обработчиков .equ F_CPU = 8000;частота процессора .equ i2c_sarp = 0b00000000 // Start-Addr_R-Read-Stop Это режим простого чтения. Например из слейва или из епрома с текущего адреса .equ i2c_sawp = 0b10000000 // Start-Addr_W-Write-Stop Это режим простой записи. .equ i2c_sawsawp = 0b10000001 // Start-Addr_W-WrPageAdr-Write-Stop Это режим с предварительной записью нужного адреса страницы в 1 байт а потом запись .equ i2c_saw2sawp = 0b10000011 // Start-Addr_WrPageAdrH-WrPageAdrL-Write-Stop Это режим с предварительной записью нужного адреса страницы в 2 байт а потом запись .equ i2c_sawsarp = 0b00000001 // Start-Addr_W-WrPageAdr-rStart-Addr_R-Read-Stop Это режим с предварительной записью нужного адреса страницы в 1 байт а потом чтение .equ i2c_saw2sarp = 0b00000011 .DSEG ;"******" - нужно вносить изменения в основном цикле!!!!!! I2C_SlaveAdres: .byte 1;регистр с адресом слэйва****************** I2C_busy: .byte 1; байт флага занятости шины и2с 1-занято! 0-свободно! I2C_ERR: .byte 1;байт для ошибок I2C_DO: .byte 1;задание, читать или записывать, 2 байта адрес или 1?********** I2C_LOW_ADRES: .byte 1;младший байт адреса ячейки для чтения/записи(если адрес однобайтовый, то младший единственный)******** I2C_HIGH_ADRES: .byte 1;старший байт адреса ячейки для чтения/записи*************** I2C_KOL_BYTE: .byte 1; сколько байт нужно прочесть или записать? писать количетсво!!!!*********** I2C_BUFER: .byte 5; байты, которые хотим пропихнуть************* I2c_ADRES_BUFER_IN: .byte 2;младший и старший байты адреса начала буфера данных для приема!*************** I2C_ADRES_BUFER_OUT: .byte 2;младший и старший байты адреса начала буфера данных для отправки!**************** I2C_INDEX_DATA: .byte 1;размер смещения,т.е. сколько байт уже отправлено, вначале отправки должен ранвться 0! TWSI:;перрывание i2c PUSHF;р16 и sreg в стэк PUSH R17;в стек PUSH R18 PUSH R0;в стек PUSH R30;в стек PUSH R31;в стек CLR R0;нужен 0 LDI ZH,HIGH(TWI_TABLE);заносим в индексную пару адрес таблицы причины прерывания и2с LDI ZL,LOW(TWI_TABLE);и младший байт UIN R16,TWSR;кода прерывания в р16 LSR R16;сдвиг влево LSR R16;еще LSR R16;и еще ADD ZL,R16;прибавляем значение к адресу таблицы ICALL;переходим на причину прерывания POP R31;достаем из стека z пару POP R30; POP R0;р0 из стека POP R18 POP R17;р17 из стека POPF;достаем р16 и sreg RETI;выход из прерывания TWI_TABLE:;таблица прерываний RJMP TWI_0x00;0x00 Bus Fail Автобус сломался… эээ в смысле аппаратная ошибка шины. Например, внезапный старт посреди передачи бита. RJMP TWI_0x08;0x08 Start Был сделан старт. Теперь мы решаем что делать дальше, например послать адрес ведомого RJMP TWI_0x10;0x10 ReStart Был обнаружен повторный старт. Можно переключиться с записи на чтение или наоборот. От логики зависит. RJMP TWI_0x18;0x18 SLA+W+ACK Мы отправили адрес с битом записи, а в ответ получили ACK от ведомого. Значит можно продолжать. RJMP TWI_0x20;0x20 SLA+W+NACK Мы отправили адрес с битом записи, а нас послали NACK. Обидно, сгенерим ошибку или повторим еще раз. RJMP TWI_0x28;0x28 Byte+ACK Мы послали байт и получили подтверждение, что ведомый его принял. Продолжаем. RJMP TWI_0x30;0x30 Byte+NACK Мы послали байт, но подтверждение не получили. Видимо ведомый уже сыт по горло нашими подачками или он захлебнулся в данных. ;Либо его ВНЕЗАПНО посреди передачи данных украли инопланетяне. RJMP TWI_0x38;0x38 Collision А у нас тут клановые разборки — пришел другой мастер, ;по хамски нас перебил, да так, что мы от возмущения аж заткнулись. Ничего I’l be back! До встречи через n тактов! RJMP TWI_0x40;0x40 SLA+R+ACK Послали адрес с битом на чтение, а ведомый отозвался. Хорошо! Будем читать. RJMP TWI_0x48;0x48 SLA+R+NACK Крикнули в шину «Эй ты, с адресом ХХХ, почитай нам сказки» А в ответ «Иди NACK!» ;В смысле на запрос адреса с битом чтения никто не откликнулся. Видимо не хотят или заняты. Также может быть никого нет дома. RJMP TWI_0x50;0x50 Receive Byte Мы приняли байт. И думаем что бы ответить ведомому. ACK или NACK. RJMP TWI_0x58;0x58 Receive Byte+NACK Мы приняли байт от ведомого и сказали ему «иди NACK!» И он обиженый ушел, освободив шину. TWI_0x10: ;повторный старт TWI_0x08:;произвели старт! LDS R16,I2C_SlaveAdres;адрес слэйва LDS R17,I2C_DO;что нужно, запись или чтение? CPI R17,0 BRNE TWI_0x10_WR ORI R16,1<<0 TWI_0x10_WR: OUT TWDR,R16;отправляем адрес слейва по шине и2с OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;флаг преывания, блок тви и разрешаем прерывания ;TWINT флаг прерывания ;TWEA 1-ACK, 0-NACK ;TWSTA 1-start, 0-no start ;TWSTO 1-stop ;TWEN блок TWI включен ;TWIE - разрешаем прерывания TWI RET;выход из подпрерывания TWI_0x18:;подтверждение после посылки байта адреса и бита записи LDS R16,I2C_DO;загружаем тех задание в регистр SBRS R16,0;проверяем, нужно ли нам только записать байт? если да, то переход БЕЗ АДРЕСОВ! RJMP TWI_0x18_sawp;чтение тут невозможно! т.к. на чтении будет другое подпрерывание SBRC R16,0;проверяем, а не нужно ли нам послать адрес ячейки? в которую хотим писать RJMP TWI_0x18_sawsawp;если нужно , то переход. Адрес ячейки состоит из одного байта! соответственно младшего ;если ничего не подошло, значит нужно отправить адрес состоящий из двух байт ;передачу начинаем со старшего байта, затем просто в тех задании поправим на пересылку оставшегося младшего байта LDS R17,I2C_HIGH_ADRES;загружаем старший байт ANDI R16,~(1<<0);обнуляем первый бит тех задания, тем самым переводим его на отправку еще одного байта адреса(младшего) STS I2C_DO,R16 OUT TWDR,R17;загружаем старший байт адреса в тви RET;выход из подпрерывания TWI_0x18_sawsawp:;ЭТО КЛОООООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Запись только младшего байта адреса LDS R17,I2C_LOW_ADRES;загружаем младший байт адреса ячейки слейва DEC R16;первращаем sawsawp/sawsarp в просто в sawp или sarp!!!, т.е. загружаем в задание только запись! нужный байт адреса мы уже отослали! теперь только запись/чтение STS I2C_DO,R16 ;закидываем в задания OUT TWDR,R17;загружаем адрес ячейки в тви для записи OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT; передача младшего байта адреса! RET;выход из подпрерывания TWI_0x18_sawp:;ЭТО КЛОООООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! запись самих байтов ;(сюда я вставлял счетчик, сколько раз здесь бывает процессор, и все сходится) LDS R16,I2C_KOL_BYTE;считываем, сколько байт нам нужно записать???? LDS R18,I2C_INDEX_DATA;счетчик, сколько байт скинули CP R16,R18; кончились байты то? BREQ TWI_0x18_STOP;если да, то переход и СТОП!!!! говорим слейву: хватит братан, но передаем последний байт) LDS ZL,I2C_ADRES_BUFER_OUT //младший байт адреса буфера данных озу, откуда брать байты на отправку LDS ZH,I2C_ADRES_BUFER_OUT+1 //старший байт адреса буфера данных озу, откуда брать байты на отправку ADD ZL,R18;прибавляем к адресу количество байт, которые отправили ADC ZH,R0 INC R18;увеличиваем счетчик на 1 STS I2C_INDEX_DATA,R18;отправляем в озу LD R17,Z;берем один из.. байтов по адресу индексной пары ;(сюда я вставлял строчку LDI R17,1 но отправляет в итоге не одни 1, а опять таки 00 и ff) OUT TWDR,R17;отправляем в регистр для передачи OUTI TWCR,0<<TWEA|0<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;передача очередного байта данных! RET;выход из подпрерывания TWI_0x18_STOP:;СТОПЭ братан слейв,наелся ты байтов, отдохни ЭТО КЛОООН!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! STS I2C_busy,R0;освобождаем линию тви OUTI TWCR,1<<TWEA|0<<TWSTA|1<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;запись ОКОНЧЕНА! RET;выход из подпрерывания TWI_0x28: LDS R16,I2C_DO;и так, м ыздесь потому что: 1-отправили адрес и нужна запись байтов в ячейки ;2- отправили адрес и нужно чтение и 3 - отправили старший байт памяти, нужно отправить младший. CPI R16,i2c_sawp;нужна запись? BREQ TWI_0x18_sawp;переход SBRC R16,0;нужно записать оставшийся младший байт? RJMP TWI_0x18_sawsawp;переход! ;а иначе повторный старт!!!! OUTI TWCR,1<<TWEA|1<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE|1<<TWINT ;повторный старт, т.к. чтение! RET;выходи из подпрерывания .MACRO I2C_OUT;НУЖНО ПРЕДВАРИТЕЛЬНО ЗАКИНУТЬ ОТПРАВЛЯЕМЫЕ ДАННЫЕ В И2С БУФЕР!!! ;0-адрес слейва, младший байт = 0!!! ; 1-запись или чтение? если с адресом, то сколькибитный? ;2-младший байт адреса регистра слэйва ;3-старший байт адреса регистра слейва(если не нужен, то 0) ;4-сколько байт нужно записать, прочитать? ;5-какая скорость передачи нужна? ;6-откуда брать байты? CLR R16 STS I2C_INDEX_DATA,R16 LDI R16,1 STS I2C_BUSY,R16 OuTI I2C_SlaveAdres,@0 //OUTI TWAR,@0;заружаем адрес слэйва LDI R16,@1;загружаем задание STS I2C_DO,R16 .if @3>0x00 LDI ZL,LOW(@2);адрес регистра слэйва для приема/передачи LDI ZH,HIGH(@3) STS I2C_LOW_ADRES,ZL STS I2C_HIGH_ADRES,ZH .else LDI ZL,LOW(@2) STS I2C_LOW_ADRES,ZL .endif LDI R16,@4;загружаем значение количества байт для приема/передачи STS I2C_KOL_BYTE,R16 OUTI TWSR,0<<TWPS1|0<<TWPS0;предделитель 1 LDI R16,((F_CPU/@5)-16)/2;расчетскорости приема/передачи данных UOUT TWBR,R16 LDI ZL,LOW(@6) LDI ZH,HIGH(@6) STS I2C_ADRES_BUFER_OUT,ZL STS I2C_ADRES_BUFER_OUT+1,ZH OUTI TWCR,1<<TWINT|1<<TWEA|1<<TWSTA|0<<TWSTO|1<<TWEN|1<<TWIE;запуск! отправляем старт! ;TWINT флаг прерывания ;TWEA 1-ACK, 0-NACK ;TWSTA 1-start, 0-no start ;TWSTO 1-stop ;TWEN блок TWI включен ;TWIE - разрешаем прерывания TWI .ENDM Тело: OUTI I2C_BUFER,1 OUTI I2C_BUFER+1,2 I2C_OUT 0xA2,i2c_sawsawp,0x03,0,2,200,I2C_BUFER - сюда больше не вернется Main: зацикливание Rjmp main П.С. вот что пишет i2c debuger в протеусе: S A2 A 03 A 00 A FF A P
  4. attiny13 обработка кнопок

    А вот это очень даже решение проблемы) учусь по статьям Di Halta, он так же всегда советовал не давать тупить мк, а все задержки в основной цикл пихать, по факту мне надо переместить цикл задержки перед опросом кнопок и все) больше спасибо!
  5. attiny13 обработка кнопок

    Прошу прощения, что ввел вас в заблуждение) я намеренно не тстал сюда копировать таблицу прерываний, она у меня аналогична то, что вы привели. С ней все в порядке)
  6. attiny13 обработка кнопок

    все наоборот) нажатие кнопки не пропускается) если убрать задержку, то при нажатии на кнопку она программно нажимает огромное количество раз, хотя в реальности я просто тыкнул ее пальцем разок)
  7. attiny13 обработка кнопок

    Всем привет! начал осваивать программирование на ассемблере, вопрос такой, написал программу для получения стробоскопического эффекта светодиода. Период, когда он горит - 200микросекунд, период, когда он выключен регулируется от 400 микросекунд и больше. 4 кнопки, 2 из них повышают(груби и точно), другие 2 понижают аналогично. При нажатии на кнопки(после пары нажатий на увеличение) микроконтроллер выдает сплошной 0 на выходе, как я понял за одно нажатие кнопки он ее успевал обработать овер кучу раз, пришлось ввести задержку после обработки кнопки, но теперь понятное дело все вообще не плавно переключается, а чувствуется эта "тупая" задержка после каждого нажатия. Как можно программно изменить этот деффект? при этом оставив кнопки(потом хочу все делать при помощи ацп), но именно сейчас, когда я зеленый, хочу понять, каким образом задержка в данном случае не будет мешать основной программе? Макросы сюда пихать не буду, по комментариям понятно, если будут вопросы, отвечу. Все проверял, как в протеусе, так и на реальной схеме. .include "tn13def.inc";используем attiny13 ; RAM =================================================== .dseg;оперативная память count: .byte 2;выделяем 2 ячейки памяти для счетчика compare: .byte 2;выделяем 2 ячейки памяти для периода диода в выключенном состоянии ; END RAM =============================================== rjmp T0_OVF ; Timer0 Overflow Handler ; Interrupts ==============================================обработчки прерываний T0_OVF:;обработка перрывания таймера 0 по переполнению PUSHF;кладем в стек регистр Р16 и SREG PUSH R17;то же самое р17 INCM count;прибавляем к счетчику 1 POP R17;достаем р17 POPF;и р16 с SREG RETI;выход из прерывания ; End Interrupts ========================================== Reset:;предварительные настройки LDI R16,LOW(RAMEND);инициализация стека OUT SPL,R16 //инициализация таймера======================================== SETB TIMSK0,TOIE0,R20;разрешаем локальное прерывание таймера 0 OUTI TCCR0B,1<<CS00; запускаем таймер с предделителем 1 LDI R16,0b00010000 UOUT DDRB,R16 LDI R16,0b00001111 UOUT PORTB,R16 SEI;глобальное разрешение прерываний LDI R16,14;загружаем начальное значение в регистр для периода выклюения светодиода STS compare,R16;загружаем в оперативную память //конец инициализации========================================== ; Main ========================================================= Main:;тело цикла/ LDS R16,count;загружаем значение из счетчика CPI R16,7;дотикало ли до 200мс BREQ LED_OFF;если да, то переход M1: LDS R16,count;загружаем значение таймера LDS R17,compare;загружаем переменную для определения времени перерыва светодиода CP R16,R17;натикало нужное значение? BREQ LED_ON;если да, то включаем светодиод SBIS PINB,0;если нажата кнопка то повысить нерабочий период светодиода на 200мс RJMP BT1 SBIS PINB,1;если нажата кнопка, то понизить нерабочий период светодиода на 200мс RJMP BT2 SBIS PINB,2;если кнопка нажата, то повысить нерабочий период светодиода на 10мс RJMP BT3 SBIS PINB,3;если кнопка нажата, то понизить нерабочий период светодиода на 10мс RJMP BT4 LDS R20,count;сброс таймера, если по какой-либо причине LDS R21,compare;показания стали больше чем в переменной CP R21,R20; например при понижении периода нерабочего состояния BRLT L1 RJMP MAIN;все сначала ; End Main ===================================================== BT1: LDS R18,compare;грубое повышение SUBI R18,(-7) STS compare,R18 B0:;злосчастная задержка LDI R18,4 CLR R16 CLR R17 B1: Dec R17 BRNE B1 dec R16 BRNE B1 Dec R18 BRNE B1 RJMP Main BT2: LDS R18,compare;грубое снижение SUBI R18,7 STS compare,R18 RJMP B0 //RJMP Main BT3: LDS R18,compare;точное повышение SUBI R18,(-1) STS compare,R18 RJMP B0 BT4: LDS R18,compare;точное снижение SUBI R18,1 STS compare,R18 RJMP B0 LED_OFF: CLRB PORTB,4,R16;выключаем светодиод RJMP M1;возвращаемся обратно LED_ON:;включение светодиода SETB PORTB,4,R16;перестаем подавать питание L1: CLI;запрет прерываний CLR R16;нужен 0 STS count,R16;обнуляем счетчик в оперативке STS count+1,R16 OUT TCNT0,R16;обнуляем регистр таймера SEI;разрешаем прерывание RJMP MAIN;переход обратно .eseg;еепром Всем откликнувшимся спасибо! Напоминаю, только начал осваивать, могут быть нелогичные моменты.