Статья №9
Прежде, чем познакомить вас с ещё одним примером использования шины I2C, к которой подключены несколько ведомых устройств (SLAVE), я должен описать работу с подпрограммами, поскольку код без применения подпрограмм в подобных случаях будет очень длинным в силу многократного повторения некоторых его фрагментов.
Например, при подключении четырёх SLAVE к I2C обращение к ним и считывание данных будет иметь место, по крайней мере, четыре раза:
I2cstart
I2cwbyte Adress1 ‘запрос первого устройства
I2crbyte Date1, Nack ‘cчитывание данных первого устройства
I2cstop
Print “Date1=” ; Date1
. . . . . . . . .
I2cstart
I2cwbyte Adress4
I2crbyte Date4, Nack
I2cstop
Print “Data4=” ; Date4
Когда используется много подобных повторяющихся фрагментов и потребуется изменить код, вам придётся изменять код в каждом из них, что может привести к ошибкам и долгим поискам этих ошибок.
В связи с вышесказанным отметим, что преимущество применения подпрограммы в том, что повторяющиеся фрагменты кода используются в программе только один раз.
Подпрограмму можно вызвать из любого места программы. После выполнения подпрограммы основная программа продолжает свою работу с того же самого места.
Приведём пример написания подпрограммы для вышеприведённого случая:
' описание подпрограммы
Declare Sub Dateread (Byval Adress As Byte, Date As Byte)
‘ основная программа
Adress = Adress1 ‘задание адреса первого устройства
Call Dateread (Adress, Date) ‘ вызов подпрограммы
Date1 = Date
Print “Data1 =” ; Date1
. . . . . . . . . . . . . . .
Adress = Adress4 ‘задание адреса четвёртого устройства
Call Dateread (Adress, Date) ‘ вызов подпрограммы
Date4 = Date
Print “Data4 =” ; Date4
‘ подпрограмма
Sub Dateread (Byval Adress As Byte, Date As Byte)
I2cstart
I2cwbyte Adress
I2crbyte Date, Nack
I2cstop
End Sub ‘выход из подпрограммы
Команда Byval указывает подпрограмме, что заданные ей параметры должны остаться неизменными. В этом случае Bascom создаёт в памяти копию переменной и будет работать с ней. Исходная переменная останется неизменной, чтобы с ней не происходило в подпрограмме. В описанном выше примере с переменной Adress ничего не происходит , поэтому здесь Byval можно не применять, если переменная описана в начале программы.
В связи с этим следует подчеркнуть, что все переменные и подпрограммы должны быть описаны в начале программы.
На Рис.1 представлена схема подключения четырёх температурных датчиков типа Lm76 к шине I2C микроконтроллера ATtiny2313. Контроллер опрашивает последовательно каждый из датчиков. Полученные значения температуры отображаются на ЖК дисплее типа MT-16S2H и с помощью UART через преобразователь уровня МАХ3232 и разъём DB9-F по протоколу RS-232 передаются в порт персонального компьютера. Более подробно работа всех элементов схемы была описана ранее в предыдущих статьях по Bascom.
Как видно из схемы датчик Lm76 имеет два бита адреса А0 и А1, которые можно задать аппаратурно. Манипулируя подключением данных контактов к шине питания и земле, можно получить следующие адреса датчика (для считывания):
№1 – 10010001 при А0 = 0, А1 = 0
№2 – 10010011 при А0 = 1, А1 = 0
№3 – 10010101 при А0 = 0, А1 = 1
№4 – 10010111 при А0 = 1, А1 = 1.
Подробно датчик Lm76 описан в статье по Bascom №7.
На Рис.2 представлена блок – схема программы “Termometr4”. Программа состоит из основного цикла, в котором происходит опрос датчиков с помощью периодического вызова подпрограммы, отображения значений температуры на ЖКИ и передаче этих значений в терминал. В самой подпрограмме происходит считывание по I2C значения температуры датчика и его обработка ( более подробное описание см. статью по Bascom №7).
Текст программы приведён ниже. Сама программа находится в приложение 1 этой статьи.
Программа “Termometr4”:
$regfile = "attiny2313a.dat" 'настройки
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32
Config Scl = Portb.7 'конфигурация шины I2C
Config Sda = Portb.5
Config I2cdelay = 10 'частота 100 КГц
Const Tadress1 = &B10010001 'адреса термометров Lm76
Const Tadress2 = &B10010011
Const Tadress3 = &B10010101
Const Tadress4 = &B10010111
Const Lm76resolution = 0.0625 'температурный коэффициент
Config Pind.1 = Output 'конфигурация вывода TxD
Dim T1 As Single 'объявление переменных
Dim T2 As Single
Dim T3 As Single
Dim T4 As Single
Dim Highbyte As Byte
Dim Lowbyte As Byte
Dim Allbyte As Word
Dim Znak As Byte
Dim Tadress As Byte
Dim Tchannel As Single
Declare Sub Temp(byval Tadress As Byte , Tchannel As Single) 'определение подпрограммы
Do 'основная программа
Tadress = Tadress1 'считывание температуры с первого термометра
Call Temp(tadress , Tchannel) 'вызов подпрограммы считывания знач. температуры
T1 = Tchannel
Print "T1=" ; T1 'передача знач. температуры в терминал по RS-232
Lcd "T1=" ; T1 'отражение знач.температуры на ЖКИ
Wait 1 'задержка 1 сек
Tadress = Tadress2 'cчитывание знач.температуры со второго термометра
Call Temp(tadress , Tchannel)
T2 = Tchannel
Print "T2=" ; T2
Lcd "T2=" ; T2
Wait 1
Tadress = Tadress3 'считывание знач. температуры с третьего термометра
Call Temp(tadress , Tchannel)
T3 = Tchannel
Print "T3=" ; T3
Lcd "T3=" ; T3
Wait 1
Tadress = Tadress4 'считывание знач. температуры с четвёртого термометра
Call Temp(tadress , Tchannel)
T4 = Tchannel
Print "T4=" ; T4
Lcd "T4=" ; T4
Wait 1
Loop
Sub Temp(byval Tadress As Byte , Tchannel As Single) 'подпрограмма считывания температуры
I2cstart 'включение I2C
I2cwbyte Tadress 'посылка адреса термометра
I2crbyte Highbyte , Ack 'cчитывание старшего байта
I2crbyte Lowbyte , Nack 'считывание младшего байта
I2cstop 'выключение I2C
Allbyte = Makeint(lowbyte , Highbyte) 'объединение байтов
Znak = Highbyte And 128 ’ выделение знака
Cls
If Znak = 128 Then 'если знак=1 ("-")
Allbyte = Not Allbyte 'то инвертирование модуля температуры
Allbyte = Allbyte + 1 'и увеличение на единицу
Print "-"
Lcd "-"
Else
Print "+"
Lcd "+"
End If
Shift Allbyte , Right , 3 'сдвиг вправо на три бита
Tchannel = Allbyte * Lm76resolution 'определение реальной температуры
End Sub
End 'end program
Результаты симулирования программы показаны на Рис.3.