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

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

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

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


Вы здесь » Программирование ATMEL в BASCOM. » Исходники » Тестю индикатор. Правильная обработка прерываний. Как сделать?


Тестю индикатор. Правильная обработка прерываний. Как сделать?

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

1

Собрал на макетке схему семисегментного индикатора на 4 разряда с обвязкой( для выбора разрядов  ключи pnp с резисторами 1 кОм на базе, выводы сегментов через резисторы 1кОм). Получилось 4 вывода для управления выбором разрядов, 8 выводов для управления сегментами. Активный уровень управления 0 В.
Решил сделать тестовую прошивку. Начальные числа для разрядов 0, 1, 2, 3. Каждую секунду происходит инкремент числа каждого разряда. Использую динамическую индикацию, поэтому нужно переключать разряды с частотой 400 Гц(4 разряда х 100 раз в секунду для одного разряда).
Использовал два таймера в режиме совпадения - таймер1 для периода 1с( 1 Гц), таймер0 для частоты 400 Гц. Таймер1 генерирует прерывания для инкремента значений разрядов. Таймер0 отвечает за динамическую индикацию и не генерирует прерываний, а только устанавливает флаг совпадения, поэтому проверку флага и перебор разрядов нужно производить в основном цикле.
Правильно я сделал? Прошивку не тестировал ещё( боюся ;-)).
Главный вопрос - если несколько источников прерываний срабатывают одновременно, как они срабатывают по приоритету? Сначала обрабатывается прерывание с большим приоритетом, а с меньшим приоритетом затем обрабатывается автоматически или нужны махинации с регистрами? Может, поделитесь ссылками на примеры с несколькими источниками прерываний.

Код:
$regfile = "m328pdef.dat"
$crystal = 16000000

Declare Sub View(byval Digit_value As Byte , Byval Number_digit As Byte , Byval Dp_view As Byte)
' процедура вывода сегментов для отдельного разряда

Dim Digit1 As Byte , Digit2 As Byte , Digit3 As Byte , Digit4 As Byte ' значения разрядов
Dim Dp As Byte ' флаг отображения точки
Dim Next_digit As Byte ' номер отображаемого разряда в данный момент времени
Dim View_flag as Byte ' флажок в неоходимости изменения сегментов

Digit1 = 0 : Digit2 = 1 : Digit3 = 2 : Digit4 = 3
Dp = 0
Next_digit = 1 : View_flag = 0 

Restore Digits

Config Portb = Output ' управление разрядами
Config Portd = Output ' управление сегментами

Config Portb.5 = Output
Config Timer1 = Timer , Prescale = 256 , Compare_a = Disconnect , Clear_timer = 1
Compare1a = 62500  ' 1 sec
On Oc1a Pr1

Config Timer0 = Timer , Prescale = 256 , Compare_a = Disconnect , Clear_timer = 1
Ocr0a = 155   ' 400Hz

Enable Oc1a
Enable Interrupts
Start Timer1
Start Timer0

Do
   If Tifr0.1 = 1 Then
      Next_digit = Next_digit + 1
      View_flag = 1                                       ' разряд изменился - сегменты надо обновить на другие
      Tifr0.1 = 1                                           ' сброс флага ocr1a
   End If
   If Next_digit > 4 Then
      Next_digit = 1
   End If
   If View_flag = 1 Then
      Select Case Next_digit
         Case 1 : Call View(digit1 , Next_digit , 0)        
         Case 2 : Call View(digit2 , Next_digit , 0)
         Case 3 : Call View(digit3 , Next_digit , 0)
         Case 4 : Call View(digit4 , Next_digit , 0)
      End Select
   View_flag = 0 ' сброс флажка обновления
   End If
Loop

Sub View(digit_value As Byte , Number_digit As Byte , Dp_view As Byte)
'Local L1 As Byte
'L1 = Number_digit
Portd = 255
Select Case Number_digit
   Case 1 : Portb = &B00001110
   Case 2 : Portb = &B00001101
   Case 3 : Portb = &B00001011
   Case 4 : Portb = &B00000111
End Select
Portd = Lookup(digit_value , Digits)
End Sub

Pr1:
Digit1 = Digit1 + 1
Digit2 = Digit2 + 1
Digit3 = Digit3 + 1
Digit1 = Digit4 + 1
If Digit1 > 9 Then
   Digit1 = 0
End If
If Digit2 > 9 Then
   Digit2 = 0
End If
If Digit3 > 9 Then
   Digit3 = 0
End If
If Digit4 > 9 Then
   Digit4 = 0
End If
Return

End

Digits:
Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001
Data &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

Отредактировано Sikorsky (2017-04-12 23:16:21)

0

2

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

если несколько источников прерываний срабатывают одновременно, как они срабатывают по приоритету? Сначала обрабатывается прерывание с большим приоритетом, а с меньшим приоритетом затем обрабатывается автоматически или нужны


"Кто раньше встал, того и тапки". У Atmega нет приоритетов на прерывания. Обрабатывается первое поступившее, затем все последующие, они не пропадают, если конечно не сбросить флаг о происшедшем прерывании.

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

Может, поделитесь ссылками на примеры с несколькими источниками прерываний

Варианты

Семисегментные индикаторы

Отредактировано sasha_1973 (2017-04-13 05:30:33)

0

3

Протестил индикатор. Программу изменил. Всё завязано на один таймер теперь.

Код:
$regfile = "m328pdef.dat"
$crystal = 16000000
Declare Sub View(byval Digit_value As Byte , Byval Number_digit As Byte , Byval Dp_view As Byte)

Restore Digits
Config Portd = Output
Portd = 255
Config Portb = Output
Portb = 0
Dim Var As Byte , Buffer As Word
Dim Digit1 As Byte , Digit2 As Byte , Digit3 As Byte , Digit4 As Byte       ' значения разрядов
Dim Dp As Byte                                              ' флаг отображения точки
Dim Next_digit As Byte

Digit1 = 0 : Digit2 = 1 : Digit3 = 2 : Digit4 = 3
Dp = 0
Next_digit = 1

Var = 0
Buffer = 62500
On Oc1a Pr
Ocr1ah = High(buffer)
Ocr1al = Low(buffer)
Tccr1a = 0
Tccr1b = 12
Enable Oc1a
Enable Interrupts

Do
If Next_digit < 4 Then
Next_digit = Next_digit + 1
Else
Next_digit = 1
End If
Select Case Next_digit
   Case 1 : Call View(digit1 , Next_digit , 0)
   Case 2 : Call View(digit2 , Next_digit , 0)
   Case 3 : Call View(digit3 , Next_digit , 0)
   Case 4 : Call View(digit4 , Next_digit , 0)
End Select
Waitms 5
Loop

Sub View(digit_value As Byte , Number_digit As Byte , Dp_view As Byte)
Portd = 255
Select Case Number_digit
   Case 1 : Portb = &B00001110
   Case 2 : Portb = &B00001101
   Case 3 : Portb = &B00001011
   Case 4 : Portb = &B00000111
End Select
Portd = Lookup(digit_value , Digits)
End Sub
Pr:

If Digit1 < 9 Then
   Digit1 = Digit1 + 1
Else
   Digit1 = 0
End If

If Digit2 < 9 Then
   Digit2 = Digit2 + 1
Else
   Digit2 = 0
End If

If Digit3 < 9 Then
   Digit3 = Digit3 + 1
Else
   Digit3 = 0
End If

If Digit4 < 9 Then
   Digit4 = Digit4 + 1
Else
   Digit4 = 0
End If

Return

End

Digits:
Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001
Data &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

0

4

Фото собранной макетной платы.
http://sf.uploads.ru/t/Tfj2o.png

0

5

Очень странный метод реализации динамической индикации.
Совершено не понятно для чего нужно использовать два таймера, а динамическую индикацию осуществлять в основном цикле. Как до такого можно додуматься? :O  Это же вообще не логично... :dontknow:

Динамическая индикация на примере термометра вместе с проектом для протеуса. http://pure-basic.narod.ru/forum_files/ … mo_Led.rar

Код:
$regfile = "m8def.dat"                                      ' Выбор типа контроллера.
$crystal = 1000000                                          ' Частота генератора, Гц.
$hwstack = 50                                               ' Размер аппаратного.
$swstack = 30                                               ' и программных стеков.
$framesize = 40

Declare Sub Termo()

'Config Base = 0
Config 1wire = Portb.0
Config Portd = Output
Config Portc = Output

Dim Dinamindex As Byte
Dim Temp As Byte
Dim Dinaminfo(4) As Byte
Dim 1wire_array(9) As Byte                                  ' Объявление массивов
Dim Currenttermo As Word At 1wire_array Overlay

Portc = 0
For Temp = 1 To 4
 Dinaminfo(temp) = 10
Next Temp


Config Timer0 = Timer , Prescale = 64                       ' Конфигурация таймера Timer1.
On Timer0 Dinam                                             'Nosave                                      ' Назначение подпрограммы прерываний от Timer1
Enable Timer0                                               ' Разрешение прерываний от Timer1

Enable Interrupts

Do
   1wreset                                                  ' Сброс датчика.
   1wwrite &HCC                                             ' Команда "Skip ROM".
   1wwrite &H44                                             ' Команда "Convert  T".
   Waitms 800
   1wreset                                                  ' Сброс датчика.
   1wwrite &HCC                                             ' Команда "Skip ROM"
   1wwrite &HBE
   1wire_array(1) = 1wread(2)
   If Err = 0 Then                                          '1wire_array(9) = Crc8(1wire_array(1) , 8) Then
     Call Termo()
   End If
Loop
End

Sub Termo()
  Stop Timer0

   If 1wire_array(2).7 = 1 Then
     Toggle Currenttermo
     Incr Currenttermo
     Dinaminfo(4) = 10
   Else
     Dinaminfo(4) = 11
   End If

   Temp = 1wire_array(1) And 15
   Dinaminfo(1) = Lookup(temp , Ds_dec)
   Shift Currenttermo , Right , 4
   Dinaminfo(2) = 1wire_array(1) Mod 10
   Dinaminfo(3) = Currenttermo / 10

 Start Timer0
End Sub


Dinam: ' Обработчик прерывания от Timer0 - динамическая индикация.

 DinamIndex = DinamIndex + 1
 If Dinamindex > 4 Then Dinamindex = 1

 Temp = Dinaminfo(dinamindex)

 Portc = 0
 Portd = Lookup(temp , Ind)
 If Dinamindex = 2 Then Portd.7 = 0
 Temp = 1
 Decr Dinamindex
 Shift Temp , Left , Dinamindex
 Incr Dinamindex

 Portc = Temp

Return

Ind:
Data &B11000000                                             ' 0
Data &B11111001                                             ' 1
Data &B10100100                                             ' 2
Data &B10110000                                             ' 3
Data &B10011001                                             ' 4
Data &B10010010                                             ' 5
Data &B10000010                                             ' 6
Data &B11111000                                             ' 7
Data &B10000000                                             ' 8
Data &B10010000                                             ' 9
Data &B10111111                                             ' -
Data &B11111111                                             ' Пусто

Ds_dec:
Data 0 , 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 5 , 6 , 7 , 7 , 8 , 9 , 9

+1

6

Накинулись... сами-то раньше вопросы и похуже задавали  :D
Пусть человек учится а остальное со временем придёт, и прерывания тоже  :flag:

0

7

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

Протестил индикатор. Программу изменил. Всё завязано на один таймер теперь


Если не секрет, чего это должно получиться ?

0

8

Сделал версию демо-программы, в которой все основные действия вынес в прерывания. Каждую секунду инкрементируется значение каждого разряда. А так хочу кодовый замок сделать, но не обычный, а квестовый.

Код:
$regfile = "m328pdef.dat"
$crystal = 16000000
Declare Sub View(byval Digit_value As Byte , Byval Number_digit As Byte , Byval Dp_view As Byte)

Restore Digit_segments
Config Portd = Output
Portd = 255
Config Portb = Output
Portb = 0

Dim Current_digit As Byte , I As Word
Dim Digits(4) As Byte                                       ' çíà÷åíèÿ ðàçðÿäîâ
Dim Dp As Byte                                              ' ôëàã îòîáðàæåíèÿ òî÷êè
Dim Next_digit As Byte

Digits(1) = 0 : Digits(2) = 1 : Digits(3) = 2 : Digits(4) = 3
Dp = 0
Next_digit = 1:


On Oc1a Pr_1
Ocr1ah = High(62500)
Ocr1al = Low(62500)
Tccr1a = 0
Tccr1b = 12

On Oc2a Pr_2
Ocr2a = 200
Tccr2a = 2
Tccr2b = 5

Enable Oc1a
Enable Oc2a
Enable Interrupts

Do
Waitms 5
Loop

Sub View(digit_value As Byte , Number_digit As Byte , Dp_view As Byte)
Portd = 255
Select Case Number_digit
   Case 1 : Portb = &B00001110
   Case 2 : Portb = &B00001101
   Case 3 : Portb = &B00001011
   Case 4 : Portb = &B00000111
End Select
Portd = Lookup(digit_value , Digit_segments)
End Sub

Pr_1:

For I = 1 To 4
If Digits(i) < 9 Then
   Digits(i) = Digits(i) + 1
Else
   Digits(i) = 0
End If
Next I

Return

Pr_2:

If Next_digit < 4 Then
Next_digit = Next_digit + 1
Else
Next_digit = 1
End If
Call View(digits(next_digit) , Next_digit , 0)
Return

End

Digit_segments:
Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001
Data &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

0

9

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

Код:
$regfile = "m328pdef.dat"
$crystal = 16000000
Declare Sub View(byval Digit_value As Byte , Byval Number_digit As Byte , Byval Dp_view As Byte)

Restore Digit_segments
Config Portd = Output
Portd = 255
Config Portb = Output
Portb = 0

Dim Current_digit As Byte , I As Word
Dim Digits(4) As Byte                                       ' значения разрядов
Dim Dp As Byte                                              ' флаг отображения точки
Dim Next_digit As Byte
Dim Value As Byte

Digits(1) = 0 : Digits(2) = 0 : Digits(3) = 0 : Digits(4) = 0
Dp = 0
Next_digit = 1:

Didr0 = 1
Admux = 32
Adcsra = 199

On Oc2a Pr
Ocr2a = 200
Tccr2a = 2
Tccr2b = 5

Enable Oc2a
Enable Interrupts

Do
Value = Adch
Adcsra = 199
If Value < 25 Then
Digits(1) = 0
Elseif Value < 52 Then
Digits(1) = 1
Elseif Value < 77 Then
Digits(1) = 2
Elseif Value < 102 Then
Digits(1) = 3
Elseif Value < 127 Then
Digits(1) = 4
Elseif Value < 153 Then
Digits(1) = 5
Elseif Value < 178 Then
Digits(1) = 6
Elseif Value < 204 Then
Digits(1) = 7
Elseif Value < 229 Then
Digits(1) = 8
Elseif Value < 255 Then
Digits(1) = 9
End If
Loop

Sub View(digit_value As Byte , Number_digit As Byte , Dp_view As Byte)
Portd = 255
Select Case Number_digit
   Case 1 : Portb = &B00001110
   Case 2 : Portb = &B00001101
   Case 3 : Portb = &B00001011
   Case 4 : Portb = &B00000111
End Select
Portd = Lookup(digit_value , Digit_segments)
End Sub


Pr:

If Next_digit < 4 Then
Next_digit = Next_digit + 1
Else
Next_digit = 1
End If
Call View(digits(next_digit) , Next_digit , 0)
Return

End

Digit_segments:
Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001
Data &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

Отредактировано Sikorsky (2017-04-29 21:12:27)

0

10

Собранная установка на макетке для проверки ацп авра.
http://s5.uploads.ru/t/Mug3U.png

Отредактировано Sikorsky (2017-04-29 21:11:20)

0

11

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

Изучил цап для авра.

АЦП - Аналогово-цифровой преобразователь.

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

0

12

Пётр написал(а):

АЦП - Аналогово-цифровой преобразователь.

Спасибо за исправление.

0

13

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

Код:
$regfile = "m328pdef.dat"
$crystal = 16000000
Declare Sub View(byval Digit_value As Byte , Byval Number_digit As Byte , Byval Dp_view As Byte)
Declare Function Getdigit(byval Value As Byte) As Byte


Restore Digit_segments
Config Portd = Output
Portd = 255
Config Portb = Output
Portb = 0

Dim Current_digit As Byte
Dim Digits(4) As Byte                                       ' значения разрядов
Dim Dp As Byte                                              ' флаг отображения точки
Dim Next_digit As Byte
Dim Next_channel As Byte
Dim Buffer As Byte

Digits(1) = 0 : Digits(2) = 0 : Digits(3) = 0 : Digits(4) = 0
Dp = 0
Next_digit = 0
Next_channel = 1

Didr0 = 15
Admux = 32
Adcsra = 199

On Oc2a Pr
Ocr2a = 200
Tccr2a = 2
Tccr2b = 5

Enable Oc2a
Enable Interrupts

Do

Buffer = Adch
Digits(next_channel) = Getdigit(buffer)
Next_channel = Next_channel + 1
If Next_channel > 4 Then
Next_channel = 1
End If
Buffer = Next_channel - 1
Select Case Buffer
Case 0:
Admux = 32
Case 1
Admux = 33
Case 2
Admux = 34
Case 3
Admux = 35
End Select
Adcsra = 199
Waitms 10
Loop

Sub View(digit_value As Byte , Number_digit As Byte , Dp_view As Byte)
Portd = 255
Select Case Number_digit
   Case 1 : Portb = &B00001110
   Case 2 : Portb = &B00001101
   Case 3 : Portb = &B00001011
   Case 4 : Portb = &B00000111
End Select
Portd = Lookup(digit_value , Digit_segments)
End Sub

Function Getdigit(value As Byte) As Byte
If Value < 25 Then
Getdigit = 0
Elseif Value < 52 Then
Getdigit = 1
Elseif Value < 77 Then
Getdigit = 2
Elseif Value < 102 Then
Getdigit = 3
Elseif Value < 127 Then
Getdigit = 4
Elseif Value < 153 Then
Getdigit = 5
Elseif Value < 178 Then
Getdigit = 6
Elseif Value < 204 Then
Getdigit = 7
Elseif Value < 229 Then
Getdigit = 8
Elseif Value <= 255 Then
Getdigit = 9
End If
End Function



Pr:

If Next_digit < 4 Then
Next_digit = Next_digit + 1
Else
Next_digit = 1
End If
Call View(digits(next_digit) , Next_digit , 0)
Return

End

Digit_segments:
Data &B11000000 , &B11111001 , &B10100100 , &B10110000 , &B10011001
Data &B10010010 , &B10000010 , &B11111000 , &B10000000 , &B10010000

0

14

Фото собранной установки. Возник вопрос - какие есть решения для силовой части кодовых замков?
http://s8.uploads.ru/t/kxHhn.jpg

0

15

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

какие есть решения для силовой части кодовых замков?

Актуатор замка двери.Дёшево и сердито)

0


Вы здесь » Программирование ATMEL в BASCOM. » Исходники » Тестю индикатор. Правильная обработка прерываний. Как сделать?