Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
На главную   | Карта сайта | Пишите нам | В избранное
Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс.
e-mail:jobsmp@pochta.ru

Телесистемы | Электроника | Конференция «Микроконтроллеры и их применение»

Программный интерфейс I2C на СИ CV AVR. Свершилось. Мож кому пригодится.

Отправлено dshabrov (84.21.231.242) 25 марта 2010, г. 14:02


В Си я новичок, так что сильно не бейте.

Проверено с DS1307 и CE110. 3 cуток - ни одной ошибки.
В программе записи I2C (Sendi2c) проверяется наличие ответа АСК и при его отсутствии глобальная переменна Errors инкрементируется. Программа также возвращает код FF - нет ответа. 0 - АСК получен.



#include <mega8.h>
#define SCL PORTC.5
#define SDA PORTC.4

extern unsigned char Errors; //Счетчик ошибок
void delay(void); //Функция задержки при смене состояния линий SDA, SCL
//--------------------------------------------------------------------------------
unsigned char Sendi2c(unsigned char DATA){//Передача байта на шину I2C
unsigned char i; //Счетчик передаваемых бит
unsigned char j=0; //Признак ошибки:0 - АСК получен. FFh - нет АСК
unsigned char data_bit; //Переменная для выделения отдельных битов из передаваемого байта.
DDRC.4=1; //Переключить SDA на выход
for(i=0; i<8; i++) { //Для 8-и бит.
data_bit = DATA; //Делаем копию байта для передачи (для того что бы потом применять к нему маски).
data_bit = (data_bit << i); //Теперь для того что бы получить текущий бит для передачи, сдвигаем все
//число влево на значение i - первый раз это будет 0, потом 1,2,3... и так до 7.
data_bit = (data_bit & 0b10000000); //И применяем к полученному числу маску, которая будет обнулять все биты кроме самого левого,
//а так как с каждым изменением i мы будем передвигать весь байт для передачи все дальше и дальше влево,
//постепенно будет передан каждый бит числа data_byte (с восьмого по первый, как того и требудет I2C).
if(data_bit == 0) //Если текущий бит для передачи равен нулю...
{SDA=0;} //Соответственно SDA = 0
else //Иначе (если бит равен единице):
{SDA=1;} //Соответственно SDA = 1
delay(); //Задерка
SCL=1; //Подтверждаем наше решение по передаче выставленного на SDA бита (это даст ведомому сигнал к
delay(); //Задерка
SCL=0; } //Опять таки перед стробированием "опускаем" SCL
DDRC.4=0; //Перевести линию SDA на вход для считывания ACK
delay(); //Задерка
SCL=1; //Стробируем состояние SDA, давая ведомому понять что мы
delay(); //считываем линию на предмет присутствия ACK или NACK.
if(PINC.4 == 1) { //Если ответа нет, то:
Errors++; //увеличиваем счетчик ошибок
j=0xff; } //Признак ошибки:0 - АСК получен. FFh - нет АСК
SCL=0; //Возвращаем SCL в 0, если этого не сделать, ведомый так и будет удерживать на линии ACK или NACK до бесконечности.
delay(); //Задерка
DDRC.4=1; //Линия SDA снова переконфигурирована как выход.
return j; } //
//--------------------------------------------------------------------------------
unsigned char ResI2c(void) { //Прием байта с шины I2C
unsigned char DATA = 0; //Переменная для хранения принятого байта.
unsigned char i; //Счетчик бит
delay(); //Задерка
DDRC.4 = 0; //Для приема нам нужно сконфигурировать ножку на которой висит SDA как вход.
delay(); //Задерка
for(i=8; i>0; i--) //Для 8-и бит.
{ SCL=1; //Начинаем, стробируем "кадр", т.е даем понять ведомому что принимаем бит.
delay(); //
if(PINC.4 == 1) //Если ведомый выставил на SDA единицу:
//Значит будем вставлять единицу в соответствующее этому биту место. То есть при первом проходе цикла for
{DATA |= (1<<(i-1));} //i у нас равно 8, значит записывать будем в самый крайний левый бит - MSB. (но так как счет битов в байте
//начинается с 0 и до 7, а не с 1 и до 8, прийдется каждый раз отнимать единичку (а также не забудьте
//что по I2C биты всегда передаются "с конца" (7,6,5...), поэтому то мы и начинаем for c 8).
//Ну а там где передавался 0 - в соответствующих битах data_byte останутся нули.
SCL=0; //Теперь "опускаем" SCL, говоря таким образом ведомому что бы он готовил следующий бит.
delay(); } //Задерка
SCL=1; //выдать импульс NAK
delay(); //Задерка
SCL=0; //
delay(); //Задерка
DDRC.4 = 1; //
return DATA; } //Возвращаем принятый байт.
//--------------------------------------------------------------------------------
void Strti2c(void) { //Передача условия старта на шину I2C
SDA=1; //
delay(); //Задерка
SCL=1; //старт - условием считается
delay(); //Задерка
SDA=0; //отрицательный перепад на шине SDA при
delay(); //Задерка
SCL=0; } //единичном сигнале на шине SCL
//--------------------------------------------------------------------------------
void Stopi2c(void) { //Передача условия стопа на шину I2C
SDA=0; //стоп - условием считается
delay(); //Задерка
SCL=1; //положительный перепад на шине SDA при
delay(); //Задерка
SDA=1; } //единичном сигнале на шине SCL
//--------------------------------------------------------------------------------
void delay(void) {} //Для DS1307 сойдет. Для CE110 нужно 40 циклов FOR



Подпрограмма delay снижает скорость обмена по шине, тормозя SCL. Для DS1307 тормоза нужны по минимуму на кварце в 10МГц. Для CE110 ниже 40 циклов FOR сыпятся ошибки.

Программы простые и создавались для частного случая. Так что не все режимы I2C учтены. Например, что будет если Slave будет пытаться ужержать SCL вывод AVR даже думать не хочется...
К счастью не все SLAVы такие умные, да и занижение скорости по scl рулит.


Составить ответ | Вернуться на конференцию

Ответы


Отправка ответа
Имя*: 
Пароль: 
E-mail: 
Тема*:

Сообщение:

Ссылка на URL: 
URL изображения: 

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

Перейти к списку ответов | Конференция | Раздел "Электроника" | Главная страница | Карта сайта

Rambler's Top100 Рейтинг@Mail.ru
 
Web telesys.ru