Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Правильный формат адреса регистра для I2C


Правильный формат адреса регистра для I2C

Сообщений 1 страница 18 из 18

1

Всем добрый день.  Захотел сделать термометр на Atmega8 и цифровом датчике LM75a(DS1621 полный аналог, но есть в Proteus). В качестве языка программирования использую BASCOM. Среда разработки BASCOM-AVR 2.0.7.1.

Есть вот такой код. Непонятно одно - как указывать адрес регистра что бы компилятор его принял?. Нужно считать Temp из этой таблицы:
http://we.easyelectronics.ru/uploads/images/00/00/03/2011/03/15/98300a.png
http://avrdevices.ru/wp-content/uploads/2010/10/Memory-574x181.jpg

Что я там только не пробовал писать! И 00h (адрес из таблицы 1 как я понял), и 0x00, и
&H00, и Temp, и  &H11  как посоветовали на схем.нет - на все ответ один - ошибка unknown definition.

Код:
Config Sda = Portc.4
Config Scl = Portc.5
I2cinit

Const Lm75rd = &B10011111                                   'Sensor read (последняя 1 - режим чтение)

I2cstart
I2cwbyte Lm75rd
Waitms 25


Do

   Value_out = 123

   I2cstart
   I2cwbyte Lm75rd
   I2crbyte &H11                                              'РАЗОБРАТЬСЯ С ФОРМАТОМ                        '
'по идее тут считали температуру


   I2cstart
   I2cwbyte Lm75rd

   I2crbyte I2ctemp , Ack
'So you'll have to read twice... first the ,5
   I2crbyte I2ctemp , Nack
'And then the 12... we don't store the ,5
   I2cstop



'Это для динамической индикации
   Digit_temp = Value_out                                   ' разделение измеренного значения на составные части
   One = Digit_temp Mod 10                                  ' единицы

   Digit_temp = Digit_temp - One
   Digit_temp = Digit_temp / 10
   Ten = Digit_temp Mod 10                                  ' десятки

   Digit_temp = Digit_temp - Ten
   Digit_temp = Digit_temp / 10
   Hundred = Digit_temp Mod 10                              ' сотни
   Value_out = 0

Loop

0

2

Спасибо! Теперь, что бы перевести полученное значение в адекватный вид, надо использовать такой алгоритм

Если старший бит = 0, то (температура положительная)
        Сдвигаем на 5 разрядов вправо (деление на 32), чтобы избавиться от пустых младших разрядов.
        Делим на 8. (Т.е. умножаем на LSB = 0.125)
Если старший бит = 1, то (температура ниже 0)
       Находим дополнение до 2 для всего регистра.
        Сдвигаем на 5 разрядов вправо.
        Делим на 8.


Как я понимаю Tempmsb - это байт где цельная часть температуры, Templsb - байт где дробная.
Как байт предоставить в виде отдельных битов? Как полученное из датчика значение перевести в градусы Цельсия? Пробую выводить на индикатор Tempmsb, получаю 255.

И можете пожалуйста прокомментировать инициализацию перед основным циклом? Почему нельзя так?

Код:
Const Lm75rd = &B10011111                                   'Sensor read (последняя 1 - режим чтение)

I2cstart
I2cwbyte Lm75rd
Waitms 25

0

3

Пробую выводить на индикатор Tempmsb, получаю 255. И на реальном макете на столе(в комнате +27) и в протеусе с DS1621

Дополнено:

Смотрю в протеусе на состояние поротов SDA SCL, они серые, т.е. не активные, хотя вроде заданы...

Код:
$regfile = "m8def.dat"                                      'выбираем контроллер
$crystal = 4000000                                          'выбираем частоту кварца

Dim Location As Byte                                        ' всё что касается DIM это декларация переменных
Dim Digit_temp As Word
Dim Digit As Word
Dim One As Byte
Dim Ten As Byte
Dim Ss As Single
Dim Hundred As Byte
Dim Decimalpoint As Bit
Dim Value_out As Long
Dim Value_temp As Single

Dim Tempmsb As Byte                                         'Storage for the temperature
Dim Templsb As Byte                                         'Storage for the temperature

Config Portb = Output                                       ' Portd полностью выход , все 8 бит
Seven_seg_catode Alias Portb                                ' Переименуем его , чтоб работать с именем ,а не с какимто портом

Ddrc.0 = 1                                                  ' здесь займёмся катодами , поочерёдно вслючим направление на выход
Ddrc.1 = 1
Ddrc.2 = 1

An1 Alias Portc.0                                           ' Обзавём выходы катодов нужным номером катода
An2 Alias Portc.1
An3 Alias Portc.2

Config Timer0 = Timer , Prescale = 256                      ' сконфигурируем таймер - таймер , делитель на 256
On Timer0 Indication                                        '  Когда таймер переполнится произойдёт прерывание , он должен перейти в подпрограмму с именем  Indication

Const Timerpreload_0 = 182                                  ' назначим константу , сделлано так -таймер считает до 256 , пото переполняется и вызывает прирывания , тоесть по идее 4 мегагерца / 256 = 15625 килогерц, через 15625/256 = 61 герц таймер переполнится, это нам много , поэтому мы таймер заполним уже какимто число , в данном случае 182 , получается таймер считает не от нуля , а от 182 и черз 74 импулса переполнится , что соответствует частоте 205 герц , примерно 50 герц на индикатор при 4 индикаторах.
Enable Timer0                                               ' включим таймер
Enable Interrupts                                           ' включим прерывания

Config Sda = Portc.4
Config Scl = Portc.5
I2cinit


'init the LM75
I2cstart
I2cwbyte &H90
I2cwbyte &H01
I2cstop

I2cstart
I2cwbyte &H90
I2cwbyte &H18
I2cstop


Do


'Read Temperature
I2cstart
I2cwbyte &H90
I2cwbyte &H00
I2cstop

I2cstart
I2cwbyte &H91
I2crbyte Tempmsb , Ack
I2crbyte Templsb , Nack
I2cstop

If Templsb < 128 Then
   Templsb = 0
Else
   Templsb = 5
End If

Wait 1

   Value_out = Tempmsb

   Digit_temp = Value_out                                   ' разделение измеренного значения на составные части
   One = Digit_temp Mod 10                                  ' единицы

   Digit_temp = Digit_temp - One
   Digit_temp = Digit_temp / 10
   Ten = Digit_temp Mod 10                                  ' десятки

   Digit_temp = Digit_temp - Ten
   Digit_temp = Digit_temp / 10
   Hundred = Digit_temp Mod 10                              ' сотни
   Value_out = 0

Loop





Indication:

                                                 ' *-*Подпрограмма прерываний таймера, впринципе динамическая индикация
   Timer0 = Timerpreload_0                                  ' вничале подгружаем в таймер число 182 , чтоб частота индикации была 200 герц ( писал в начале )

   If Location < 3 Then                                     ' если  переменная указывающая на положене индикатора меньше 4 то
      Incr Location                                         ' увеличиваем переменную на единицу
    Else                                                    ' иначе
      Location = 1                                          ' переменная равна единице
   End If


                                            '  выключаем все атоды , иначе мы видели бы только восьмёрки
   An1 = 0
   An2 = 0
   An3 = 0

   If Location = 1 Then Digit = One                         ' здесь проверяем что к чему относится - единицы относятся ко второму рязряду
   If Location = 2 Then Digit = Ten : Decimalpoint = 1      ' дясятки и точка к третьему
   If Location = 3 Then Digit = Hundred                     ' сотни к четвёртому

   Select Case Digit
                                           ' здесь выбираем  нужные сегменты
      Case 0 : Seven_seg_catode = &B11000000                ' цифра ноль
      Case 1 : Seven_seg_catode = &B11111001
      Case 2 : Seven_seg_catode = &B10100100
      Case 3 : Seven_seg_catode = &B10110000
      Case 4 : Seven_seg_catode = &B10011001
      Case 5 : Seven_seg_catode = &B10010010
      Case 6 : Seven_seg_catode = &B10000010
      Case 7 : Seven_seg_catode = &B11111000
      Case 8 : Seven_seg_catode = &B10000000
      Case 9 : Seven_seg_catode = &B10010000                ' цифра девять

   End Select

   If Decimalpoint = 1 And Location = 2 Then Seven_seg_catode = Seven_seg_catode Or &B10000000       '  здесь включаем децимальную точку в нужном месте

   Select Case Location                                     ' включаем нужный нам катод , который выбрала программа в начале цикл
    Case 1 : An3 = 1
    Case 2 : An2 = 1
    Case 3 : An1 = 1
   End Select

Return

End

Отредактировано Anonim (2015-08-02 19:50:56)

0

4

На плате резисторы есть, в протеусе добавил - тоже самое.

0

5

Пожалуйста.
http://rghost.ru/7Z8RzS5XD вот сам проект
http://rghost.ru/8HzHWDWSl а это DS1621 для протеуса

0

6

Ваш проект работает. А вот у меня не запускается на макете. Вот фото монтажа.
http://s6.uploads.ru/t/00wpM.jpg
http://s6.uploads.ru/t/I3xBQ.jpg
У меня адрес датчика должен быть 10011111, где  1001 заданы аппаратно для lm75a,  111 заданы пинами а0 а1 а2, и последняя 1 значит что мы читаем а не записываем.
Мне непонятно как тут задается адрес. Почему он в 16ричной системе? Почему 2 раза и разные значения? 90"(16) это 10010000 в двоичной, может из за этого контроллер обращается непонятно куда и соответственно ничего толкового в ответ не получает?

Код:
'init the LM75 
I2cstart 
I2cwbyte &H90 
I2cwbyte &H01 
I2cstop 

I2cstart
I2cwbyte &H90
I2cwbyte &H18
I2cstop

P.S. Вы извините если совсем глупости на Ваш взгляд спрашиваю, но хочется научить и разобрать во всем как следует.

P.S2., а где то попадалась инфа что полные аналоги, попал в заблуждение...

Отредактировано Anonim (2015-08-03 22:24:34)

0

7

Попробовал, практически тоже самое. Если раньше при включении секунду горели нули, а потом 255, то теперь сразу 255.

А зачем инициализация за комментирована?

Код:
Config Sda = Portc.4
Config Scl = Portc.5
I2cinit

'(
   'init the LM75
   I2cstart
   I2cwbyte &H9E
   I2cwbyte &H01
   I2cstop
   I2cstart
   I2cwbyte &H9E
   I2cwbyte &H18
   I2cstop
')

Do
'Read Temperature
I2cstart
I2cwbyte &H9E
I2cwbyte &H00
I2cstop
I2cstart
I2cwbyte &H9F
I2crbyte Tempmsb , Ack
I2crbyte Templsb , Nack
I2cstop

0

8

Попробовал, все тоже самое... Даже не знаю что и делать.

0

9

Выводы A0; A1; A2  -  сидят на +5V, измените под себя.

Рабочий исходник

$map       ' Получаем карту распределения памяти компилятором Bascom
  $regfile = "m328pdef.dat"       'Документация Atmel - http://www.atmel.com/images/Atmel-8271- … mplete.pdf
  $crystal = 8000000
  $framesize = 32       ' Размер области используемой и необходимой для преобразований
  $hwstack = 40       ' Размер аппаратного стека
  $swstack = 16       ' Размер программного стека

  $baud = 38400       ' : Ucsr0a.1 = 1       ' Двойная скорость работы USART, скорость трансляции = $baud * 2

  Print "Тест USART"

  Dim Целые_high_byte As Byte
  Dim Десятые_low_byte As Byte
  Dim Десятые_single As Single
  Dim Температура_single As Single

  Config Sda = Portc.4
  Config Scl = Portc.5
  I2cinit

  Const Запись_lm75 = &B10011110
  Const Чтение_lm75 = &B10011111


  Главный_цикл:

     Gosub Чтение_температуры
     Print Температура_single ; "°C"
     Температура_single = 0

     Waitms 750

  Goto Главный_цикл
End

'===============================================================================
  Чтение_температуры:
'-------------------------------------------------------------------------------
    I2cstart
    I2cwbyte Запись_lm75
    I2cwbyte &H00
    I2cstart
    I2cwbyte Чтение_lm75
    I2crbyte Целые_high_byte , Ack
    I2crbyte Десятые_low_byte , Nack
    I2cstop

    If Целые_high_byte > 128 Then
        Температура_single = 256 - Целые_high_byte
        Температура_single = Температура_single * -1
      Else
        Температура_single = Целые_high_byte
    End If

    If Десятые_low_byte = 128 Then
        Десятые_single = 0.5
      Else
        Десятые_single = 0
    End If

    Температура_single = Температура_single + Десятые_single
'-------------------------------------------------------------------------------
  Return
'===============================================================================

Как это безобразие работает  -  видео + фото

Отредактировано sasha_1973 (2015-08-04 19:18:34)

0

10

Mrshilov написал(а):

Залейте этот хекс. http://rghost.ru/6GKCCGwyH
Если не поможет, значит беда в железе.


Это не работает.

sasha_1973.
USART у меня нет, попытался адаптировать вашу прошивку для вывода на семисегментный индикатор. Не работает, индикатор вообще мертвый. Вообще она какая то странная, если честно. Почему основной цикл реализован не при помощи Do...Loop? Разве можно писать кириллицей(Хотя вроде скомпилировалось)? Зато у вас хотя бы адреса понятно написаны... У меня эти выводы тоже на +5V. Адреса правильные в прошивке.

Код:
$map       ' Получаем карту распределения памяти компилятором Bascom
  $regfile = "m328pdef.dat"       'Документация Atmel - http://www.atmel.com/images/Atmel-8271- … mplete.pdf
  $crystal = 4000000
  $framesize = 32       ' Размер области используемой и необходимой для преобразований
  $hwstack = 40       ' Размер аппаратного стека
  $swstack = 16       ' Размер программного стека

'  $baud = 38400       ' : Ucsr0a.1 = 1       ' Двойная скорость работы USART, скорость трансляции = $baud * 2

' Print "Тест USART"


Dim Location As Byte                                        ' всё что касается DIM это декларация переменных
Dim Digit_temp As Byte
Dim Digit As Byte
Dim One As Byte
Dim Ten As Byte
Dim Ss As Single
Dim Hundred As Byte
Dim Decimalpoint As Bit

  Dim Целые_high_byte As Byte
  Dim Десятые_low_byte As Byte
  Dim Десятые_single As Single
  Dim Температура_single As Single

Config Portb = Output                                       ' Portd полностью выход , все 8 бит
Seven_seg_catode Alias Portb                                ' Переименуем его , чтоб работать с именем ,а не с какимто портом

Ddrc.0 = 1                                                  ' здесь займёмся катодами , поочерёдно вслючим направление на выход
Ddrc.1 = 1
Ddrc.2 = 1

An1 Alias Portc.0                                           ' Обзавём выходы катодов нужным номером катода
An2 Alias Portc.1
An3 Alias Portc.2

Config Timer0 = Timer , Prescale = 256                      ' сконфигурируем таймер - таймер , делитель на 256
On Timer0 Indication                                        '  Когда таймер переполнится произойдёт прерывание , он должен перейти в подпрограмму с именем  Indication

Const Timerpreload_0 = 182                                  ' назначим константу , сделлано так -таймер считает до 256 , пото переполняется и вызывает прирывания , тоесть по идее 4 мегагерца / 256 = 15625 килогерц, через 15625/256 = 61 герц таймер переполнится, это нам много , поэтому мы таймер заполним уже какимто число , в данном случае 182 , получается таймер считает не от нуля , а от 182 и черз 74 импулса переполнится , что соответствует частоте 205 герц , примерно 50 герц на индикатор при 4 индикаторах.
Enable Timer0                                               ' включим таймер
Enable Interrupts                                           ' включим прерывания



  Config Sda = Portc.4
  Config Scl = Portc.5
  I2cinit

  Const Запись_lm75 = &B10011110
  Const Чтение_lm75 = &B10011111


  Главный_цикл:



   Gosub Чтение_температуры
   'Print Температура_single ; "°C"

   Digit_temp = Температура_single                          ' разделение измеренного значения на составные части
   One = Digit_temp Mod 10                                  ' единицы

   Digit_temp = Digit_temp - One
   Digit_temp = Digit_temp / 10
   Ten = Digit_temp Mod 10                                  ' десятки

   Digit_temp = Digit_temp - Ten
   Digit_temp = Digit_temp / 10
   Hundred = Digit_temp Mod 10                              ' сотни
     Температура_single = 0

     Waitms 750






  Goto Главный_цикл






End


Indication:

                                                 ' *-*Подпрограмма прерываний таймера, впринципе динамическая индикация
   Timer0 = Timerpreload_0                                  ' вничале подгружаем в таймер число 182 , чтоб частота индикации была 200 герц ( писал в начале )

   If Location < 3 Then                                     ' если  переменная указывающая на положене индикатора меньше 4 то
      Incr Location                                         ' увеличиваем переменную на единицу
    Else                                                    ' иначе
      Location = 1                                          ' переменная равна единице
   End If


                                            '  выключаем все аноды , иначе мы видели бы только восьмёрки
   An1 = 0
   An2 = 0
   An3 = 0

   If Location = 1 Then Digit = One                         ' здесь проверяем что к чему относится - единицы относятся ко второму рязряду
   If Location = 2 Then Digit = Ten : Decimalpoint = 1      ' дясятки и точка к третьему
   If Location = 3 Then Digit = Hundred                     ' сотни к четвёртому

   Select Case Digit
                                           ' здесь выбираем  нужные сегменты
      Case 0 : Seven_seg_catode = &B11000000                ' цифра ноль
      Case 1 : Seven_seg_catode = &B11111001
      Case 2 : Seven_seg_catode = &B10100100
      Case 3 : Seven_seg_catode = &B10110000
      Case 4 : Seven_seg_catode = &B10011001
      Case 5 : Seven_seg_catode = &B10010010
      Case 6 : Seven_seg_catode = &B10000010
      Case 7 : Seven_seg_catode = &B11111000
      Case 8 : Seven_seg_catode = &B10000000
      Case 9 : Seven_seg_catode = &B10010000                ' цифра девять

   End Select

   If Decimalpoint = 1 And Location = 2 Then Seven_seg_catode = Seven_seg_catode Or &B10000000       '  здесь включаем децимальную точку в нужном месте

   Select Case Location                                     ' включаем нужный нам катод , который выбрала программа в начале цикл
    Case 1 : An3 = 1
    Case 2 : An2 = 1
    Case 3 : An1 = 1
   End Select

Return



'===============================================================================
  Чтение_температуры:
'-------------------------------------------------------------------------------
    I2cstart
    I2cwbyte Запись_lm75
    I2cwbyte &H00
    I2cstart
    I2cwbyte Чтение_lm75
    I2crbyte Целые_high_byte , Ack
    I2crbyte Десятые_low_byte , Nack
    I2cstop

    If Целые_high_byte > 128 Then
        Температура_single = 256 - Целые_high_byte
        Температура_single = Температура_single * -1
      Else
        Температура_single = Целые_high_byte
    End If

    If Десятые_low_byte = 128 Then
        Десятые_single = 0.5
      Else
        Десятые_single = 0
    End If

    Температура_single = Температура_single + Десятые_single
'-------------------------------------------------------------------------------
  Return
'==========================================================

Отредактировано Anonim (2015-08-04 19:40:42)

0

11

Готовый вариант, просто залейте кексик для LM75 -  скачать

7 seg led индикаторы с "Общим Анодом", согласно Вашей схемы в Протеусе.

http://s6.uploads.ru/t/zFZXt.jpg http://s2.uploads.ru/t/J3aqm.jpg

Отредактировано sasha_1973 (2015-08-04 22:43:19)

0

12

Anonim написал(а):

Почему основной цикл реализован не при помощи Do...Loop?


Один из множества вариантов.

Anonim написал(а):

Разве можно писать кириллицей(Хотя вроде скомпилировалось)?


Bascom - исключение из правил, прекрасно переваривает кириллицу, где-то на форуме есть страстные дебаты по этому поводу.

Отредактировано sasha_1973 (2015-08-04 22:57:04)

+1

13

Вариант с ОА + ОК  -  скачать

Видео работы в железе  -  скачать

Тип индикатора выбирается в исходнике    "Const Type_of_indicator = 0       ' Если "0" - индикатор с общим катодом, если "1" - индикатор с общим анодом"

http://s2.uploads.ru/t/KPBEI.jpg http://s6.uploads.ru/t/eWmOx.jpg

Отредактировано sasha_1973 (2015-08-04 23:49:36)

0

14

Вопрос:

А почему собственно LM75 ?

0

15

Спасибо за помощь! Сделали все за меня, даже лишнее  :blush:
Вариант для индикаторов на выбор не качал, у меня с общим анодом. Но при прошивке

sasha_1973 написал(а):

Готовый вариант, просто залейте кексик для LM75 -  скачать

почему то показывает -1. (с точкой на 3ем разряде). Но это наверное у меня что то с железом, буду разбираться.

Программа очень подробно закомментирована, за это отдельный РЕСПЕКТ, буду вникать!

LM75a - купил пару лет назад что было в наличии, сейчас дошли руки сделать.

0

16

Anonim написал(а):

почему то показывает -1. (с точкой на 3ем разряде). Но это наверное у меня что то с железом, буду разбираться.

У Вас в железе, не подключен 4 разряд, показывает с десятыми.

Если надо 3 разряда, исправьте:

    Const Const_количество_разрядов = 4 

и

    If Флаг_знак_температуры <> 0 Then
        Температура_str = Format(температура_str , "+  0")
      Else
        Температура_str = Format(температура_str , "    0")
    End If

на следующее:

Const Const_количество_разрядов = 3

и

    If Флаг_знак_температуры <> 0 Then
        Температура_str = Format(температура_str , "+ 0")
      Else
        Температура_str = Format(температура_str , "  0")
    End If

0

17

Я это понимаю, я просто подключил разряды 2,3,4 если считать как для 4х сегментного индикатора. Все равно на 1 выводиться только минус при больших отрицательных температурах, которые я дома не создам.

Код поправил, все равно -1. показывает(индикатор подключил как было изначально). Может сам датчик битый... Вот это конечно будет обидно, как это можно достоверно проверить?.

0

18

Скиньте то, что у Вас есть мне на mail, я проверю в железе.

0


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Правильный формат адреса регистра для I2C