Опубликовано 2010-02-27 09:55:03 автором MRS

Подключение к микроконтроллеру семисегментного индикатора. Урок AVR 3


В предыдущем уроке мы научились мигать светодиодом. Этот урок ненамного сложнее, здесь мы научимся мигать 7 светодиодами. Но не просто семь светодиодов, а семисегментный индикаторсемисегментный индикатор.

Семисегментные индикаторы - это светодиоды, размещенные в определённом порядке, так что зажигая одновременно несколько светодиодов, можно формировать на индикаторе символы и цифры. Индикаторы бывают с общим катодом (минусом) и с общим анодом (плюсом). Это значит, что все семь светодиодов соединены плюсом или минусом. Например, возьмём индикатор с общим катодом и попробуем на нём что-нибудь вывести, например цифру 1. Для этого нам нужно включить светодиоды B и С. Берем наш atmega8 и подключаем к семисегментнику по схеме схема подключения семисегментника к мк Пишем простую программу, которая выведет цифру 1

#include <mega8.h> 
void main(void) 
{ 
PORTB=0x00; 
DDRB=0b00000001; //делаем ножку PB0 выходом 
 
PORTD=0b00000110; //  выводим на ножки PB1 и PB2 лог единицу, чтобы зажечь цифру 1 
DDRD=0b01111111;  //Делаем ножки PB0-PB6 выходами 
 
while (1) {} 
}
Смотрим на результат и радуемся! А как на счёт того, чтобы вывести любую цифру от 0 до 9? Для этого нам придется немножко усложнить нашу программу. Напишем процедуру out для вывода цифр от 0 до 9.
#include <mega8.h> 
#include <delay.h> 
unsigned char numder[]=  //определяем массив, в котором индекс будет соответствовать выводимой цифре 
{  
  0b00111111,  //цифра 0 
  0b00000110,  //цифра 1 
  0b01011011,  //цифра 2 
  0b01001111,  //цифра 3 
  0b01100110,  //цифра 4 
  0b01101101,  //цифра 5 
  0b01111101,  //цифра 6 
  0b00000111,  //цифра 7 
  0b01111111,  //цифра 8 
  0b01101111,  //цифра 9 
}; 
 
void out(unsigned char num) 
{ 
 PORTD=numder[num]; 
} 
 
void main(void) 
{ unsigned char i=0; 
PORTB=0x00; 
DDRB=0b00000001; //делаем ножку PB0 выходом 
 
PORTD=0b0000000; 
DDRD=0b01111111;  //Делаем ножки PB0-PB6 выходами 
      
while (1)  
{ 
 out(i++); 
 delay_ms(1000);//задержка в 1 секунду 
} 
}

Результат вывод на семисегментный индикатор Семисегментным индикатором можно управлять статически и динамически. При статическом управлении информация на разряды выводится постоянно, до этого мы рассматривали статическое управление. Динамическое управление - это поочередное зажигание разрядов индикатора с частотой, которую не воспринимает человеческий глаз. Схема подключения в этом случае выглядит так: динамический вывод на семисегментный индикатор Теперь в нашем коде мы меняем всего одну строчку DDRB=0b00000001; на DDRB=0b00000011; //делаем ножку PB0 и PB1 выходом и смотрим результат. динамический вывод на семисегментник У нас на обоих разрядах выводятся одинаковые цифры, а нам нужно, например, на первом выводить цифру 1, а на втором цифру 7. Когда на первом мы будем выводить цифру "один", второй разряд при этом выключен. В следующий момент времени выключаем первый, а на второй выводим цифру "7". Для отключения поочередно первого и второго разрядов мы будем устанавливать разные лог уровни на PD0 и PD1.
#include <mega8.h> 
#include <delay.h> 
unsigned char numder[]=  //определяем массив, в котором  индексу будут соответствовать бити на порте D 
{   
  0b00111111,  //цифра 0 
  0b00000110,  //цифра 1 
  0b01011011,  //цифра 2 
  0b01001111,  //цифра 3 
  0b01100110,  //цифра 4 
  0b01101101,  //цифра 5 
  0b01111101,  //цифра 6 
  0b00000111,  //цифра 7 
  0b01111111,  //цифра 8 
  0b01101111,  //цифра 9 
}; 
 
void out(unsigned char num) 
{   
 PORTD=numder[num]; 
} 
 
void main(void) 
{ unsigned char z=0; 
PORTB=0x00; 
DDRB=0b00000011; //делаем ножку PB0 и PB1 выходом 
 
PORTD=0b0000000; 
DDRD=0b01111111;  //Делаем ножки PB0-PB6 выходами  
while (1)  
{ 
  if (z==0) //если z=0, то выводим первую цифру 
  { 
   out(1); //выводим 1 
   PORTB=0b00000001;  // включаем семисегментник, который висит катодом на ножке PB0 
  } 
  if (z==1)  //если z=1 выводим вторую цифру 
  { 
    out(7);    // выводим цифру 7 
    PORTB=0b00000010; // Включаем семисегментник на ножке PB1 
  }  
  if (++z>1) z=0; // увеличиваем z на единицу и проверяем, не больше ли он 1. Если больше, то в z записываем 0 
 delay_ms(40);  //Делаем задержку в 40 милисекунд, это 25 выводов за секунду 
} 
}

Давайте все это приаккуратим:
  1. Сделаем, чтобы мы могли вызвать процедуру out, передав ей любое число от 0 до 99, и она сама решит, на какой сегмент какую цифру выводить
  2. Уберем логику вывода на дисплей из главного цикла и поместим ее в таймер, например на timer0
#include <mega8.h> 
#include <delay.h> 
unsigned char chislo[2];   //определяем массив из двух элементов типа char  беззнаковый(unsigned) 
unsigned char numder[]=  //определяем массив, в котором  индексу будут соответствовать бити на порте D 
{  
  0b00111111,  //цифра 0 
  0b00000110,  //цифра 1 
  0b01011011,  //цифра 2 
  0b01001111,  //цифра 3 
  0b01100110,  //цифра 4 
  0b01101101,  //цифра 5 
  0b01111101,  //цифра 6 
  0b00000111,  //цифра 7 
  0b01111111,  //цифра 8 
  0b01101111,  //цифра 9 
}; 
unsigned char i=0; // переменная для определения, на какой разряд семисегментника выводить число 
// прерывания по переполнению   timer0 
interrupt [TIM0_OVF] void timer0_ovf_isr(void) 
{ 
  PORTD=numder[ chislo[i]  ];  
  PORTB=i+1; //включаем определённый разряд семисегментника 
  if (++i>1) i=0; 
} 
 
void out(unsigned char num) 
{   
/*сначала нам нужно определить, из скольких десятков и единиц состоит выводимое число. 
Например, передали мы "45", нам надо его разложить на 4 и 5, чтобы на первый разряд семисегментника  
вывести цифру 4, а на второй - 5 */ 
 chislo[0]=num%10; //оператор % дает остаток от целочисленного деления, например 34%10 будет 4 
 chislo[1]=num/10; //  узнаем, сколько десятков в числе 
} 
 
void main(void) 
{ 
unsigned char z=0; // переменная, которая будет выводится на дисплей 
PORTB=0x00; 
DDRB=0b00000011; //делаем ножку PB0 и PB1 выходом 
 
PORTD=0b0000000; 
DDRD=0b01111111;  //Делаем ножки PB0-PB6 выходами  
 
TCCR0=0x03; //устанавливаем предделитель таймера 
TCNT0=0x64; // число, с которого таймер начинает считать до 255 
 
TIMSK=0x01; // прерывания по переполнению таймера 0 
#asm("sei") //разрешаем прерывания 
 
while (1)  
{ 
  out(z++); // выводим  значение переменной  z и увеличиваем ее на 1 
 delay_ms(1000);  //Делаем задержку в 40 милисекунд, это 25 выводов за секунду 
} 
}

В следующей статье расскажу, как к микроконтроллеру подключить lcd дисплей.

Комментарии - (4)

  • Сергей говорит:
    Все примеры замечательно работают как на симуляторе, так и в железе. Вопрос, как дописать программу динамического вывода символов для 4-х разрядного индикатора и с повторяющимся циклом. Очень нужно. Заранее спасибо.
  • Admin говорит:
    Все делается по аналогии. Узнать сколько тысяч сотен десятков и единиц, и вывести их.
  • dethdron говорит:
    Спасибо получилось, а как привязать к кнопкам ? делаю программу при нажатии на кнопку-1 светодиод-1 горит при отпускании гаснет,при нажатии на кнопку-2 светодиод-2 горит при отпускании гаснет. Со светодиодами работает а как сделать так же что бы на индикаторе нажал один горит 1 нажал два горит 2? изначально у меня так #include <mega8.h> void main (void) { DDRD = 0x00; //порт D - вход PORTD = 0xFF; //подключаем нагрузочный резистор DDRB = 0xFF; //порт B - выход PORTB = 0x00; //устанавливаем 0 на выходе while(1) { PORTB = ~PIND; //~ знак поразрядного инвертирования } }
    • Admin говорит:
      Нужно в цикл While добавить проверку на нажатия кнопки, если нажата то выводить номер нажатой кнопки, например так
      while (1)
      {
      if (PIND.0==0) out(1);
      if (PIND.1==0) out(2);
      delay_ms(1000); //Делаем задержку в 40 милисекунд, это 25 выводов за секунду
      }
      }

Добавить комментарий

Для отправки комментария вы должны авторизоваться.