|
Вопрос по битовым операциям в AtmelStudio |
|
|
|
Aug 17 2012, 17:25
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Здравствуйте, несколько месяцев назад пересел с CodeVisionAVR на AtmelStudio, и соответственно возникло непонимание как работать с портами и выводить в них определенные биты из имеющегося байта и т.д. Вот пример кода который был раньше написал в CodeVisionAVR : (Это функция вывода двоичного числа в регистр последовательного сдвига 74HC595) Код unsigned char bin_digits[10]= { 0b0000, //0 0b1000, //1 0b0100, //2 0b1100, //3 0b0010, //4 0b1010, //5 0b0110, //6 0b1110, //7 0b0001, //8 0b1001, //9 };
void HC595_write(unsigned char d0, unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4, unsigned char d5) //функция записи данных в регистр 74HC595 (используя PORTD.0=DS, PORTD.1=SH_CP, PORTD.2=ST_CP) { unsigned char i,j; unsigned char dig[6]; dig[0]=d0; dig[1]=d1; dig[2]=d2; dig[3]=d3; dig[4]=d4; dig[5]=d5; for(j=0;j<=5;j++) { for(i=0; i<=3; i++) //цикл для последовательного вывода 4 бит данных из массива { PORTD.0=bin_digits[dig[j]] & (1<<i);//выводим "текущий бит" в линию DS PORTD.1=1; //выводим "0" в линию SH_CP PORTD.1=0; //выводим "1" в линию SH_CP - считываем бит на входе регистра (считывание происходит по переднему фронту импульса на SH_CP) } } PORTD.2=1; //выводим "1" в линию ST_CP - "защелкиваем данные" ("защелкивание" происходит по переднему фронту импульса на ST_CP) PORTD.2=0; //выводим "0" в линию ST_CP } Я немного перепилил код для AtmelStudio: Код #define SH_CP 1 #define ST_CP 2 #define DS 0 unsigned char bin_digits[10]= { 0b0000, //0 0b1000, //1 0b0100, //2 0b1100, //3 0b0010, //4 0b1010, //5 0b0110, //6 0b1110, //7 0b0001, //8 0b1001, //9 };
void HC595_write(unsigned char d0, unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4, unsigned char d5) //функция записи данных в регистр 74HC595 (используя PORTD.0=DS, PORTD.1=SH_CP, PORTD.2=ST_CP) { unsigned char i,j; unsigned char dig[6]; dig[0]=d0; dig[1]=d1; dig[2]=d2; dig[3]=d3; dig[4]=d4; dig[5]=d5; for(j=0;j<=5;j++) { for(i=0; i<4; i++) //цикл для последовательного вывода 4 бит данных из массива { PORTD|=(bin_digits[dig[j]] & (1<<i))<<DS; //выводим "текущий бит" в линию DS PORTD&=(0<<SH_CP); //выводим "0" в линию SH_CP PORTD|=(1<<SH_CP); //выводим "1" в линию SH_CP - считываем бит на входе регистра (считывание происходит по переднему фронту импульса на SH_CP) } } PORTD|=(1<<ST_CP); //выводим "1" в линию ST_CP - "защелкиваем данные" ("защелкивание" происходит по переднему фронту импульса на ST_CP) PORTD&=(0<<ST_CP); //выводим "0" в линию ST_CP } И эта функция перестала работать. Я думаю что вся проблема в этой "PORTD|=(bin_digits[dig[j]] & (1<<i))<<DS;" строке. Вопрос - как в AtmelStudio вывести в конкретный бит порта один определенный бит из заданного ранее байта (в данном случае полу-байта, так как в массиве "bin_digits[10]" каждое число передается четырьмя битами) ?
Сообщение отредактировал endasm - Aug 17 2012, 17:26
|
|
|
|
|
Aug 17 2012, 17:38
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 17 2012, 20:25)  Вопрос - как в AtmelStudio вывести в конкретный бит порта один определенный бит из заданного ранее байта? Например так: Код void OutBitFromByte(unsigned char out_bit_num, unsigned char input_bit_num, unsigned char input_byte) { unsigned char port=PORTA; port&=~(1<<out_bit_num); if (input_byte&(1<<input_bit_num)) port|=(1<<out_bit_num); PORTA=port; } Можно еще через битовые поля в структурах.
|
|
|
|
|
Aug 17 2012, 18:55
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Не заработало. Что я написал не правильно?(( Код #define SH_CP 1 #define ST_CP 2 #define DS 0 unsigned char bin_digits[10]= { 0b0000, //0 0b1000, //1 0b0100, //2 0b1100, //3 0b0010, //4 0b1010, //5 0b0110, //6 0b1110, //7 0b0001, //8 0b1001, //9 }; void OutBitFromByte(unsigned char out_bit_num, unsigned char input_bit_num, unsigned char input_byte) { unsigned char port=PORTD; port&=~(1<<out_bit_num); if (input_byte&(1<<input_bit_num)) port|=(1<<out_bit_num); PORTD=port; void HC595_write(unsigned char d0, unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4, unsigned char d5) //функция записи данных в регистр 74HC595 (используя PORTD.0=DS, PORTD.1=SH_CP, PORTD.2=ST_CP) { unsigned char i,j; unsigned char dig[6]; dig[0]=d0; dig[1]=d1; dig[2]=d2; dig[3]=d3; dig[4]=d4; dig[5]=d5; for(j=0;j<=5;j++) { for(i=0; i<4; i++) //цикл для последовательного вывода 4 бит данных из массива { OutBitFromByte(DS,i,bin_digits[dig[j]]); //PORTD|=(bin_digits[dig[j]] & (1<<i))<<PORTD0; //выводим "текущий бит" в линию DS PORTD&=(0<<SH_CP); //выводим "0" в линию SH_CP PORTD|=(1<<SH_CP); //выводим "1" в линию SH_CP - считываем бит на входе регистра (считывание происходит по переднему фронту импульса на SH_CP) } } PORTD|=(1<<ST_CP); //выводим "1" в линию ST_CP - "защелкиваем данные" ("защелкивание" происходит по переднему фронту импульса на ST_CP) PORTD&=(0<<ST_CP); //выводим "0" в линию ST_CP }
|
|
|
|
|
Aug 17 2012, 19:07
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 17 2012, 21:55)  Не заработало. Что я написал не правильно? Как минимум это: Код PORTD&=(0<<SH_CP); //выводим "0" в линию SH_CP Так вы просто все линии порта обнуляете. Попробуйте так: Код PORTD&=~(1<<SH_CP); //выводим "0" в линию SH_CP
|
|
|
|
|
Aug 17 2012, 19:11
|

Местный
  
Группа: Свой
Сообщений: 321
Регистрация: 20-01-11
Из: г. Мытищи
Пользователь №: 62 366

|
Цитата(_Артём_ @ Aug 17 2012, 23:07)  Как минимум это: Код PORTD&=(0<<SH_CP); //выводим "0" в линию SH_CP Попробуйте так: Код PORTD&=~(1<<SH_CP); //выводим "0" в линию SH_CP Сдвиг нуля это конечно оригинальная(бестолковая) операция!
|
|
|
|
|
Aug 17 2012, 19:19
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Почему бестолковая, там же 1 была, вот на место той единицы "двигаем" ноль. Так всегда делал =) Цитата(_Артём_ @ Aug 17 2012, 22:07)  Как минимум это: Код PORTD&=(0<<SH_CP); //выводим "0" в линию SH_CP Так вы просто все линии порта обнуляете. Попробуйте так: Код PORTD&=~(1<<SH_CP); //выводим "0" в линию SH_CP Нет не все, так как я сдвигаю 0 на значение "SH_CP" - тоесть на 1, и в итоге на втором бите порта имеем "0".
|
|
|
|
|
Aug 17 2012, 19:57
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 17 2012, 22:19)  Почему бестолковая, там же 1 была, вот на место той единицы "двигаем" ноль. Чо, звучит логично - задвинули на нужное место ноль. Цитата(endasm @ Aug 17 2012, 22:19)  Так всегда делал =) И что работало? Это новое слово в науке и технике! Цитата(endasm @ Aug 17 2012, 22:19)  Нет не все, так как я сдвигаю 0 на значение "SH_CP" - тоесть на 1, и в итоге на втором бите порта имеем "0". Все несколько не так происходит: АВР не может задвигать врегистр порта бита. Происходит так: 1)в какойто регистр (R0-R32) пишется число 0<<SH_CP, то есть ноль. 2)потом какой-нибудь командой (например STS ADD(PORTD),R16) регистр копируется в PORT. Цитата(endasm @ Aug 17 2012, 22:19)  Нет не все, так как я сдвигаю 0 на значение "SH_CP" - тоесть на 1, и в итоге на втором бите порта имеем "0". У вас где-то такое работало? Приведите пример, что ли. Может это PIC был? Хотя и там наврядли.
|
|
|
|
|
Aug 17 2012, 20:15
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Хм, вы заставили меня задуматься, сейчас ещё раз всё перепроверю. Да ладно вам, всё работает. Вот например кусок такой мигает светодиодом: Код #define SH_CP 0
int main(void) { DDRD=0b11111111; while(1) { PORTD|=(1<<SH_CP); _delay_ms(1000); PORTD&=(0<<SH_CP); _delay_ms(1000); } } Всё прекрасно сдвигается.
Сообщение отредактировал endasm - Aug 17 2012, 20:16
|
|
|
|
|
Aug 17 2012, 20:30
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 17 2012, 23:15)  Да ладно вам, всё работает. Шутим? Цитата(endasm @ Aug 17 2012, 23:15)  Вот например кусок такой мигает светодиодом: Код #define SH_CP 0
int main(void) { DDRD=0b11111111; while(1) { PORTD|=(1<<SH_CP); _delay_ms(1000); PORTD&=(0<<SH_CP); _delay_ms(1000); } } Если светодиод на порту PD0, то да, согласен, будет мигать. И что? Цитата(endasm @ Aug 17 2012, 23:15)  Всё прекрасно сдвигается. Это не сдвиг. Код: Код PORTD&=(0<<SH_CP); можно понять как PORTD=PORTD&0; Остальные биты регистра порта обнуляются тоже. Посмотрите дизассемблером, если не верите.
|
|
|
|
|
Aug 17 2012, 20:38
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Цитата(_Артём_ @ Aug 17 2012, 23:30)  Шутим? Если светодиод на порту PD0, то да, согласен, будет мигать. И что? Это не сдвиг. Код: Код PORTD&=(0<<SH_CP); можно понять как PORTD=PORTD&0; Остальные биты регистра порта обнуляются тоже. Посмотрите дизассемблером, если не верите. Аа, Вы абсолютно правы, только что проверил. Просто от работы в CodeVision с его PORTD.0 и т.д совсем я думать перестал. Сейчас всё поправлю и снова испробую.
|
|
|
|
|
Aug 17 2012, 21:11
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Можно так написать Код for(i=0;i<6;i++) { temp=dig[i]; //temporary for(j=0;j<4;j++) { if(temp & 0x01) PORTD |= _BV(DS) //DS=1 else PORTD &= ~_BV(DS); //or DS=0 PORTD |= _BV(SH_CP); //SH_CP=1 PORTD &=~_BV(SH_CP); //SH_CP=0 temp >>=1; //shift right } } тогда массив bin_digits[10] не нужен
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Aug 17 2012, 21:28
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Да, исправил и всё работает. Функция выводит информацию в 74HC595. Но вот с остальным кодом тоже проблемы. Вообще-то я никак не доделаю часы, отображающие время при помощи газоразрядных ламп. Схему и фотографии прилагаю. Написал весь код для них, но в итоге на лампы выводятся на первый взгляд случайные цифры, некоторые гаснут периодически. Также прикрепил весь код для них. Может кто приблизительно скажет что может быть не так ? Код не очень большой. http://dl.dropbox.com/u/42063417/IMG_0182.JPGhttp://dl.dropbox.com/u/42063417/IMG_0184.JPGДумаю что ошибка всё-таки заключается в программном способе реализации протокола I2C.
Эскизы прикрепленных изображений
|
|
|
|
|
Aug 17 2012, 22:07
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 18 2012, 00:28)  Думаю что ошибка всё-таки заключается в программном способе реализации протокола I2C. Наверняка. И зачем его вообше делать программным, если есть вполне ребочий аппаратный? Код void i2c_start(void) //Функция генерации стартового условия { DDRC|=(1<<SDA); //Для I2C используем PORTC DDRC|=(1<<SCL); PORTC=(1<<SDA)|(1<<SCL); asm("nop"); PORTC&=~(1<<SDA); asm("nop"); PORTC&=~(1<<SCL); } Может, я ошибаюсь, но мне кажется что в i2с вывод единицы в порт не должен использоваться, только "0" и "Z". Не знаю какая у вас тактовая, но есть такая особенность i2c - slave может задерживать передачу бита, удерживая SCL в 0. А в вашей программе биты тактируются как в spi, не глядя на состояние шины.
|
|
|
|
|
Aug 18 2012, 06:13
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Ну в I2C же только мастер тактирует ни смотря ни на что. И вот в один момент времени когда и SDA и SCL подняты - SDA опускается к нулю - стартовое условие (и небольшая задержка), потом и SCL опускается в 0.
|
|
|
|
|
Aug 18 2012, 06:37
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Цитата(=GM= @ Aug 18 2012, 00:11)  Можно так написать Код for(i=0;i<6;i++) { temp=dig[i]; //temporary for(j=0;j<4;j++) { if(temp & 0x01) PORTD |= _BV(DS) //DS=1 else PORTD &= ~_BV(DS); //or DS=0 PORTD |= _BV(SH_CP); //SH_CP=1 PORTD &=~_BV(SH_CP); //SH_CP=0 temp >>=1; //shift right } } тогда массив bin_digits[10] не нужен ого, круто получилось )). Только я не пойму одного, в "temp" хранится десятичное число. Как же с ним производить такие операции можно? Разве не нужно в двоичный вид переводить?
|
|
|
|
|
Aug 18 2012, 06:46
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Программный I2C был вынужденной мерой так как аппаратная его реализация мне сложновата.
|
|
|
|
|
Aug 18 2012, 08:03
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (_Артём_ @ Aug 18 2012, 01:07)  Может, я ошибаюсь, но мне кажется что в i2с вывод единицы в порт не должен использоваться, только "0" и "Z". Именно. Автор наступил на грабли, по которым прошлись почти все создатели программного I2C. Вот в этой теме подробное объяснение. А вот еще одна на ту же тему.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 20 2012, 11:41
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Вот сделал аппаратную реализацию TWI. Но на лампах одни нули отображаются, при попытке прогнать прогу в AVR симуляторе он вообще зависает(. Где может быть ошибка? PS: на осциллографе смотрю SDA и SCL - они всегда подняты. Код unsigned char twi(unsigned char action) { switch(action) { case TWI_START: case TWI_RESTART: TWCR = _BV(TWSTA) | _BV(TWEN) | _BV(TWINT) | _BV(TWIE); break; case TWI_STOP: TWCR = _BV(TWSTO) | _BV(TWEN) | _BV(TWINT) | _BV(TWIE); break; case TWI_TRANSMIT: TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWIE); break; case TWI_RECEIVE_ACK: TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWEA)| _BV(TWIE); break; case TWI_RECEIVE_NACK: TWCR = _BV(TWEN) | _BV(TWINT) | _BV(TWIE); break; } if(action != TWI_STOP)while (!(TWCR & _BV(TWINT))); return (TWSR & 0b11111000); }
unsigned char i2c_read(unsigned char adr_slave, unsigned char adr_byte) { unsigned char readed_byte; twi(TWI_START); //формируем сигнал START TWDR=adr_slave; //загружаем адрес slave на запись twi(TWI_TRANSMIT); //передаем адрес TWDR=adr_byte; //загружаем адрес байта twi(TWI_TRANSMIT); //передаем twi(TWI_RESTART); //формируем рестарт (RESTART) TWDR=adr_slave|1; //загружаем адрес DS1307 на чтение twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); //получаем подтверждение от slave readed_byte=TWDR; //в "readed_byte" записываем принятый байт twi(TWI_RECEIVE_NACK); //после чтения байта формируем NACK - больше данные не нужны twi(TWI_STOP); //формируем сигнал STOP return readed_byte; }
void i2c_send(unsigned char adr_slave, unsigned char adr_byte, unsigned char data_byte) { twi(TWI_START); //формируем сигнал START TWDR=adr_slave; //загружаем адрес slave на запись twi(TWI_TRANSMIT); //передаем адрес TWDR=adr_byte; //загружаем адрес байта twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); //получаем подтверждение от slave TWDR=data_byte; //загружаем байт данных twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); // twi(TWI_STOP); //формируем сигнал STOP }
Сообщение отредактировал endasm - Aug 20 2012, 12:52
|
|
|
|
|
Aug 20 2012, 13:11
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Я хочу симуляции программы, что бы можно было видеть на каких выводах что и когда происходит.
|
|
|
|
|
Aug 20 2012, 13:22
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(endasm @ Aug 20 2012, 16:11)  Я хочу симуляции программы Хотеть не вредно. Пишите симулятор который поддерживает TWI или Может какой протеус симулирует что-нибудь... Цитата(endasm @ Aug 20 2012, 16:11)  что бы можно было видеть на каких выводах что и когда происходит. Тут нужен логический анализатор или что-то навроде того.
|
|
|
|
|
Aug 20 2012, 13:40
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Цитата(_Артём_ @ Aug 20 2012, 16:22)  Хотеть не вредно. Пишите симулятор который поддерживает TWI или Может какой протеус симулирует что-нибудь...
Тут нужен логический анализатор или что-то навроде того. Я не знал что симулятор в Atmel Studio не работает с TWI. Просто там даже регистры TWI просматривать можно и всё такое.
Сообщение отредактировал endasm - Aug 20 2012, 13:41
|
|
|
|
|
Aug 20 2012, 19:54
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(ILYAUL @ Aug 20 2012, 22:17)  Тогда все биты TWSR устанавливайте сами , ручками Так конечно можно пропихнуть i2c-пакет через симулятор, но чем это поможет? Потом также гадать почему не работает? Мне кажется более разумным такое: так как есть индикатор, то можно его задействовать для вывода отладочной информации: Код unsigned char i2c_debug_log[DEBUG_BUFFER_SIZE]; i2c_debug_log[0]=twi(TWI_START); //формируем сигнал START TWDR=adr_slave; //загружаем адрес slave на запись i2c_debug_log[1]=twi(TWI_TRANSMIT); //передаем адрес TWDR=adr_byte; //загружаем адрес байта i2c_debug_log[2]=twi(TWI_TRANSMIT); //передаем
..... // вывод на индикатор for (i=0; i<DEBUG_BUFFER_SIZE; i++) { OutToIndicator(debug_log[i]); delay_ms(3000); } delay_ms(10000); Лучше конечно ComPort подходит, но тоже вариант.
|
|
|
|
|
Aug 20 2012, 23:10
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 9-07-12
Пользователь №: 72 673

|
Ура, всё заработало - часы исправно идут. Не хватало лишь вот такой строчки в функции вывода чисел на лампы "DDRD=(1<<DS)|(1<<SH_CP)|(1<<ST_CP);" :D Вот весь код: Код #include <avr/io.h> #include <util/twi.h>
#define DS 0 #define SH_CP 1 #define ST_CP 2
#define adr_ds1307 0b11010000 //адресс на запись в ds1307
#define TWI_START 0 #define TWI_RESTART 1 #define TWI_STOP 2 #define TWI_TRANSMIT 3 #define TWI_RECEIVE_ACK 4 #define TWI_RECEIVE_NACK 5
unsigned char bin_digits[10]= { 0b0000, //0 0b1000, //1 0b0100, //2 0b1100, //3 0b0010, //4 0b1010, //5 0b0110, //6 0b1110, //7 0b0001, //8 0b1001, //9 };
unsigned char twi(unsigned char action) { switch(action) { case TWI_START: case TWI_RESTART: TWCR = (1<<TWSTA) | (1<<TWEN) | (1<<TWINT) | (1<<TWIE); break; case TWI_STOP: TWCR = (1<<TWSTO) | (1<<TWEN) | (1<<TWINT) | (1<<TWIE); break; case TWI_TRANSMIT: TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWIE); break; case TWI_RECEIVE_ACK: TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWEA)| (1<<TWIE); break; case TWI_RECEIVE_NACK: TWCR = (1<<TWEN) | (1<<TWINT) | (1<<TWIE); break; } if(action != TWI_STOP) while (!(TWCR & (1<<TWINT))); return (TWSR & 0b11111000); }
unsigned char i2c_read(unsigned char adr_slave, unsigned char adr_byte) { unsigned char readed_byte; twi(TWI_START); //формируем сигнал START TWDR=adr_slave; //загружаем адрес slave на запись twi(TWI_TRANSMIT); //передаем адрес TWDR=adr_byte; //загружаем адрес байта twi(TWI_TRANSMIT); //передаем twi(TWI_RESTART); //формируем рестарт (RESTART) TWDR=adr_slave|1; //загружаем адрес DS1307 на чтение twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); //получаем подтверждение от slave readed_byte=TWDR; //в "readed_byte" записываем принятый байт twi(TWI_RECEIVE_NACK); //после чтения байта формируем NACK - больше данные не нужны twi(TWI_STOP); //формируем сигнал STOP return readed_byte; }
void i2c_send(unsigned char adr_slave, unsigned char adr_byte, unsigned char data_byte) { twi(TWI_START); //формируем сигнал START TWDR=adr_slave; //загружаем адрес slave на запись twi(TWI_TRANSMIT); //передаем адрес TWDR=adr_byte; //загружаем адрес байта twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); //получаем подтверждение от slave TWDR=data_byte; //загружаем байт данных twi(TWI_TRANSMIT); //передаем twi(TWI_RECEIVE_ACK); // twi(TWI_STOP); //формируем сигнал STOP }
void OutBitFromByte(unsigned char out_bit_num, unsigned char input_bit_num, unsigned char input_byte) { unsigned char port=PORTD; port&=~(1<<out_bit_num); if (input_byte&(1<<input_bit_num)) port|=(1<<out_bit_num); PORTD=port; }
//===========================================функция записи данных в регистр 74HC595===========================================
void HC595_write(unsigned char d0, unsigned char d1, unsigned char d2, unsigned char d3, unsigned char d4, unsigned char d5) { DDRD=(1<<DS)|(1<<SH_CP)|(1<<ST_CP); unsigned char i,j; unsigned char dig[6]; dig[0]=d0; dig[1]=d1; dig[2]=d2; dig[3]=d3; dig[4]=d4; dig[5]=d5; for(j=0;j<=5;j++) { for(i=0; i<4; i++) //цикл для последовательного вывода 4 бит данных из массива { OutBitFromByte(DS,i,bin_digits[dig[j]]); PORTD&=~(1<<SH_CP); //выводим "0" в линию SH_CP PORTD|=(1<<SH_CP); //выводим "1" в линию SH_CP - считываем бит на входе регистра } } PORTD|=(1<<ST_CP); //выводим "1" в линию ST_CP - "защелкиваем данные" PORTD&=~(1<<ST_CP); //выводим "0" в линию ST_CP }
int main(void) { TWSR &= ~(1<<TWPS0)|(1<<TWPS1); //биты предделителя TWBR=114; //Настраиваем частоту шины //(при 8MHz F_CPU получаем 8000000/(2*(16+114)) = 32kHz) unsigned char h10, h1, m10, m1, s10, s1; //объявляем переменной для хранения значений часов, минут, секунд unsigned char temp_byte; temp_byte=i2c_read(adr_ds1307, 0x00); if(temp_byte & 0b10000000) //проверяем 8-ой бит (если он "CH" = 1 - значит часы не запущены) { i2c_send(adr_ds1307,0x00,0b00000000); //запускаем часы DS1307 } i2c_send(adr_ds1307,0x07,0b0010000); //задаём частоту генерации на SQW = 1 Hz while(1) { //============секунды================== temp_byte=i2c_read(adr_ds1307, 0x00); //считываем байт значений секунд s1= (temp_byte & 0b00001111); //выделяем значение единиц секунд s10=(temp_byte & 0b11110000)>>4; //выделяем значение десятков секунд //============минуты=================== temp_byte=i2c_read(adr_ds1307, 0x01); //считываем байт значений минут m1= (temp_byte & 0b00001111); m10=(temp_byte & 0b11110000)>>4; //============часы===================== temp_byte=i2c_read(adr_ds1307, 0x02); //считываем байт значений часов h1= (temp_byte & 0b00001111); h10=(temp_byte & 0b11110000)>>4;
HC595_write(h10,h1,m10,m1,s10,s1); //записываем данные в регистры 74HC595 } }
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|