Atmega 16 не дружит с 74hc595

Тема в разделе "Микроконтроллеры AVR", создана пользователем maxpayn, 14 мар 2019.

Метки:
  1. Вы не используете сброс триггеров сдвига. Ваш код должен гарантированно сдвигать за цикл данные 8 раз. Чтоб после следующего цикла записи, биты данных оказывались в "родных" местах. Проверьте это.
    Выглядеть святее Папы Римского - не особое достоинство.

    3/ Подвесьте прямо на микре между 16-м и 8-м выводами керамический кондер 0,1 Мкф и электролит 10 мкф. 595-е сильно шумят по питанию. Делал приемник "От Насти" на РадиоКоте - видел капризы 595-х.
     
    Последнее редактирование: 15 мар 2019
    maxpayn и Andrey12 нравится это.
  2. ostrov

    ostrov Гуру

    Протеус (даже купленный) это совсем не то же самое что реальная схема. В нем нет помех и соплей. 595 работают отлично, если все сделать правильно. А любителям краденного софта я желаю тоже работать бесплатно.
     
    Limoney и parovoZZ нравится это.
  3. 1/ Помехи и сопли жевать хорошо после того, как Протеус покажет, что код работает как надо. Если в нем есть логические ошибки, на помехи и сопли грешить - только время терять.
    2/ 99,999% читателей форума, читают с экранов, сделанных в Поднебесной, где глубоко плевать на "краденный софт" или не краденный, как и технологии. Строить из себя святых, а пользоваться краденным без зазрения совести ?. Не абсурд ? Уж лучше Самоделкины гоняют ворованный софт, на который у них элементарно нет денег, чем колются и бухают по подворотням. Иначе "не любителям ворованного софта" (выросшим как пить дать на сп***нной Мелкософтовской операционке) будет часто некомфортно на улице по вечерам. Придет время, если разбогатеют - заплатят.
    ПС. Это флуд. Извиняюсь. Но расставить точки над i - дело не вредное.
     
    Последнее редактирование: 16 мар 2019
  4. Swyters

    Swyters Нуб

    Можно продолжить тему, чтоб не плодить новую?
    Решил научиться работать с 595-й. Взял attiny2313, фьюзы прошиты на 8 МГц (без делителя). Подключение 595-й описано в коде. Пробовал вариант посадки пин 13 не на землю, а объединять с пин 12, как кое-где рекомендуют, разницы нет. Семисегментный индикатор с общим катодом, знакоместа управляются напрямую с МК, сегменты - через сдвиговый регистр. Писал в CodeVisionAVR, худо-бедно все работает, код ниже:

    Код (C++):
    /*******************************************************
    Chip type               : ATtiny2313
    AVR Core Clock frequency: 8,000000 MHz
    Memory model            : Tiny
    External RAM size       : 0
    Data Stack size         : 32

    Подключение SN75HC595:
    -----------------------
    9 - Q7` - для единственной микросхемы, для нескольких микросхем (последняя в цепи) -> не подключено
            - для нескольких микросхем (не последняя в цепи) -> к DS следующей микросхемы
    10 - MR -> к питанию
    11 - SH-CP -> к МК (для нескольких микросхем все SH-CP объединены одной шиной)
    12 - ST-CP -> к МК (для нескольких микросхем все ST-CP объединены одной шиной)
    13 - OE -> к земле
    14 - DS - единственная микросхема -> к МК
            - вторая и т.д. микросхема -> к Q7` предыдущей микросхемы
    *******************************************************/


    #include <tiny2313.h>
    #include <stdio.h>
    #include <delay.h>
    #define DS PORTB.0      //    DS  (pin14 74HC595)
    #define SH_CP PORTB.1   // SH-CP  (pin11 74HC595)
    #define ST_CP PORTB.2   // ST-CP  (pin12 74HC595)

    // Declare your global variables here
    //--- Двоичное обратное ---- 0 --------- 1 --------- 2 --------- 3 --------- 4 --------- 5 --------- 6 -------- 7 ---------- 8 --------- 9 ---//
      unsigned char segm[] = {0b11111100, 0b01100000, 0b11011010, 0b11110010, 0b01100110, 0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11110110};
    // Обратное представление, переписанное справа-налево от младших разрядов к старшим, нужно для прямого занесения в сдвиговый регистр

    // массив знакомест - подключены напрямую к МК  ->  PORTB.3 .. PORTB.6
    volatile unsigned char disp[] = {0, 0, 0, 0};
    int up = 0;

    void show_dig() {
      unsigned char i,j;
      unsigned char symb;
      for (i=0;i<4;i++) {    // цикл для знакоместа
        PORTB |= (1<<6) | (1<<5) | (1<<4) | (1<<3);  // гасим все знакоместа
        symb = disp[i];
        for (j=0;j<8;j++) {  // цикл для сдвигового регистра
          DS=symb&1;         // пишем в регистр
          SH_CP=1;           // сдвиг в регистре
          SH_CP=0;
          symb>>=1;          // следующий бит
        }
        delay_us(50);
        ST_CP=1;             // защелка, выдаем данные на выходы регистра
        delay_us(50);
        ST_CP=0;
        PORTB &= (~(1<<(i+3)));  // включаем нужное знакоместо
        delay_ms(2);  
      }  
    }


    void main(void)
    {
    // Declare your local variables here
    int k;

    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);              
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    // Input/Output Ports initialization
    // Port A initialization
    // Function: Bit2=In Bit1=In Bit0=In
    DDRA=(0<<DDA2) | (0<<DDA1) | (0<<DDA0);
    // State: Bit2=T Bit1=T Bit0=T
    PORTA=(0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

    // Port B initialization
    // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=Out Bit1=Out Bit0=Out
    DDRB=(0<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
    // State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=0 Bit1=0 Bit0=0
    PORTB=(0<<PORTB7) | (1<<PORTB6) | (1<<PORTB5) | (1<<PORTB4) | (1<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

    // Port D initialization
    // Function: Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
    DDRD=(0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
    // State: Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
    PORTD=(0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Normal top=0xFF
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
    TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
    TCNT0=0x00;
    OCR0A=0x00;
    OCR0B=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer1 Stopped
    // Mode: Normal top=0xFFFF
    // OC1A output: Disconnected
    // OC1B output: Disconnected
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
    TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=(0<<TOIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<ICIE1) | (0<<OCIE0B) | (0<<TOIE0) | (0<<OCIE0A);

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    // Interrupt on any change on pins PCINT0-7: Off
    GIMSK=(0<<INT1) | (0<<INT0) | (0<<PCIE);
    MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);

    // USI initialization
    // Mode: Disabled
    // Clock source: Register & Counter=no clk.
    // USI Counter Overflow Interrupt: Off
    USICR=(0<<USISIE) | (0<<USIOIE) | (0<<USIWM1) | (0<<USIWM0) | (0<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);

    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: Off
    // USART Transmitter: On
    // USART Mode: Asynchronous
    // USART Baud Rate: 9600
    UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
    UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
    UCSRC=(0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
    UBRRH=0x00;
    UBRRL=0x33;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // The Analog Comparator's positive input is
    // connected to the AIN0 pin
    // The Analog Comparator's negative input is
    // connected to the AIN1 pin
    ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
    // Digital input buffer on AIN0: On
    // Digital input buffer on AIN1: On
    DIDR=(0<<AIN0D) | (0<<AIN1D);


    #asm("sei");
    delay_ms(500);

    while (1)
    {
      if (up++ > 9999) up = 0;   // просто переменная для отображения
      for (k=0;k<4;k++) {        // "разбодяжка" переменной по знакоместам
        switch(k) {
          case 0:          
            disp[k] = segm[up % 10000 / 1000];
            break;                        
          case 1:
            disp[k] = segm[up % 1000 / 100];
            break;
          case 2:
            disp[k] = segm[up % 100 / 10];
            break;
          case 3:
            disp[k] = segm[up % 10];                                                                
            break;
        }
      }  
      show_dig();      // отображаем на индикаторе
    }
    }
    Продолжение следует...
     
    Последнее редактирование: 26 мар 2019
  5. Swyters

    Swyters Нуб

    Потом решил перенести индикацию в прерывание таймера. И начались чудеса. При старте отображается первоначальное значение 0 и все. Если перенести переменную в тело прерывания и проводить все операции с ней там - все работает.
    Похоже, что прерывание крутится непрерывным циклом, не передавая управление в основную программу. Если в обработчике прерывания его запретить, а в теле основного цикла вновь разрешить - все работает.
    Не пойму в чем косяк, может кто подскажет?
    Код с прерыванием:
    Код (C++):
    /*******************************************************
    Chip type               : ATtiny2313
    AVR Core Clock frequency: 8,000000 MHz
    Memory model            : Tiny
    External RAM size       : 0
    Data Stack size         : 32

    Подключение SN75HC595:
    -----------------------
    9 - Q7` - для единственной микросхемы, для нескольких микросхем (последняя в цепи) -> не подключено
            - для нескольких микросхем (не последняя в цепи) -> к DS следующей микросхемы
    10 - MR -> к питанию
    11 - SH-CP -> к МК (для нескольких микросхем все SH-CP объединены одной шиной)
    12 - ST-CP -> к МК (для нескольких микросхем все ST-CP объединены одной шиной)
    13 - OE -> к земле
    14 - DS - единственная микросхема -> к МК
            - вторая и т.д. микросхема -> к Q7` предыдущей микросхемы
    *******************************************************/


    #include <tiny2313.h>
    #include <stdio.h>
    #include <delay.h>
    #define DS PORTB.0      //    DS  (pin14 74HC595)
    #define SH_CP PORTB.1   // SH-CP  (pin11 74HC595)
    #define ST_CP PORTB.2   // ST-CP  (pin12 74HC595)

    // Declare your global variables here
    //--- Двоичное обратное ---- 0 --------- 1 --------- 2 --------- 3 --------- 4 --------- 5 --------- 6 -------- 7 ---------- 8 --------- 9 ---//
      unsigned char segm[] = {0b11111100, 0b01100000, 0b11011010, 0b11110010, 0b01100110, 0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11110110};
    // Обратное представление, переписанное справа-налево от младших разрядов к старшим, нужно для прямого занесения в сдвиговый регистр

    // массив знакомест - подключены напрямую к МК  ->  PORTB.3 .. PORTB.6
    volatile unsigned char disp[] = {0, 0, 0, 0};
    int up = 0;

    interrupt [TIM0_COMPA] void timer0_compa_isr(void) {
    unsigned char i,j;
    unsigned char symb;
      TIMSK &= (~(1<<OCIE0A));
      for (i=0;i<4;i++) {    // цикл для знакоместа
        PORTB |= (1<<6) | (1<<5) | (1<<4) | (1<<3);  // гасим все знакоместа
        symb = disp[i];
        for (j=0;j<8;j++) {  // цикл для сдвигового регистра
          DS=symb&1;         // пишем в регистр
          SH_CP=1;           // сдвиг в регистре
          SH_CP=0;
          symb>>=1;          // следующий бит
        }
        delay_us(50);
        ST_CP=1;             // защелка, выдаем данные на выходы регистра
        delay_us(50);
        ST_CP=0;
        PORTB &= (~(1<<(i+3)));  // включаем нужное знакоместо
        delay_ms(2);
      }
    }


    void main(void)
    {
    // Declare your local variables here
    int k;

    // Crystal Oscillator division factor: 1
    #pragma optsize-
    CLKPR=(1<<CLKPCE);
    CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0);          
    #ifdef _OPTIMIZE_SIZE_
    #pragma optsize+
    #endif

    // Input/Output Ports initialization
    // Port A initialization
    // Function: Bit2=In Bit1=In Bit0=In
    DDRA=(0<<DDA2) | (0<<DDA1) | (0<<DDA0);
    // State: Bit2=T Bit1=T Bit0=T
    PORTA=(0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

    // Port B initialization
    // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=Out Bit1=Out Bit0=Out
    DDRB=(0<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
    // State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=0 Bit1=0 Bit0=0
    PORTB=(0<<PORTB7) | (1<<PORTB6) | (1<<PORTB5) | (1<<PORTB4) | (1<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

    // Port D initialization
    // Function: Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
    DDRD=(0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0);
    // State: Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
    PORTD=(0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Normal top=0xFF
    // OC0A output: Disconnected
    // OC0B output: Disconnected
    TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
    TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (1<<CS00);
    TCNT0=0x00;
    OCR0A=0xFF;
    OCR0B=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer1 Stopped
    // Mode: Normal top=0xFFFF
    // OC1A output: Disconnected
    // OC1B output: Disconnected
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
    TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=(0<<TOIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<ICIE1) | (0<<OCIE0B) | (0<<TOIE0) | (1<<OCIE0A);

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    // Interrupt on any change on pins PCINT0-7: Off
    GIMSK=(0<<INT1) | (0<<INT0) | (0<<PCIE);
    MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);

    // USI initialization
    // Mode: Disabled
    // Clock source: Register & Counter=no clk.
    // USI Counter Overflow Interrupt: Off
    USICR=(0<<USISIE) | (0<<USIOIE) | (0<<USIWM1) | (0<<USIWM0) | (0<<USICS1) | (0<<USICS0) | (0<<USICLK) | (0<<USITC);

    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: Off
    // USART Transmitter: On
    // USART Mode: Asynchronous
    // USART Baud Rate: 9600
    UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
    UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
    UCSRC=(0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
    UBRRH=0x00;
    UBRRL=0x33;

    // Analog Comparator initialization
    // Analog Comparator: Off
    // The Analog Comparator's positive input is
    // connected to the AIN0 pin
    // The Analog Comparator's negative input is
    // connected to the AIN1 pin
    ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
    // Digital input buffer on AIN0: On
    // Digital input buffer on AIN1: On
    DIDR=(0<<AIN0D) | (0<<AIN1D);


    #asm("sei");
    delay_ms(500);

    while (1)
    {
      if (up++ > 9999) up = 0;   // просто переменная для отображения
      for (k=0;k<4;k++) {        // "разбодяжка" перемнной по знакоместам
        switch(k) {
          case 0:      
            disp[k] = segm[up % 10000 / 1000];
            break;                      
          case 1:
            disp[k] = segm[up % 1000 / 100];
            break;
          case 2:
            disp[k] = segm[up % 100 / 10];
            break;
          case 3:
            disp[k] = segm[up % 10];                                                            
            break;
        }
      }
      TIMSK |= (1<<OCIE0A);
    }
    }
     
    Последнее редактирование: 26 мар 2019
  6. maxpayn

    maxpayn Нуб

    Проковырявшись обнаружил что пины PC2-PC5 это пины отладчика JTAG, и что бы они работали как I/O то надо выключить JTAG в фьюзах, и желательно еще в коде.
    А вот почему не работает PB0 и PB1 - непонятно
     
  7. parovoZZ

    parovoZZ Гуру

    Нет. При выходе из прерывания МК выполняет одну следующую инструкцию из кода и только потом прыгает опять в прерывание.
     
  8. Swyters

    Swyters Нуб

    Понятно, что в теории все именно так. Вопрос, почему у меня так получается?
     
  9. parovoZZ

    parovoZZ Гуру

    В симуляторе гоняй. Как там колдует кодвижн - ХЗ. Делал бы как все - в атмел студии - было б проще.
    Ну и комментарии на русском вперемешку с ангельским как-бы намекает...
     
  10. znamen

    znamen Гик

    Ото пусть Ариадна и делает сдвиги в сдвиговом регистре протеусом. И верит этому протеусу на слово.
    Какая наивность.
     
  11. Swyters

    Swyters Нуб

    Если я начинающий, то мне проще так, как я начал. Когда-нибудь и до Студии дойдем. И в симуляторе тоже учиться работать надо.
    А на что это намекает, кроме того, что это автоматически сгенеренный текст CodeVision'ом при создании нового проекта?
     
  12. parovoZZ

    parovoZZ Гуру

    Да не чему там учиться. По шагам смотришь, какие регистры какие значения принимают ну и считаешь такты, чтобы уложиться меж вызовов прерываний. Я считал такты на не занятом таймере с прескалером=1. Ну то есть включаешь его в симуляторе и он начинает тикать. Очень удобно.
     
  13. Тупо скомпилил в CV оба варианта. Загнал в Протеус - оба работают. Счёт и сканирование со скоростью ок. 125 ед/сек. Для дисплея - это не правильно .
    ПС. С КодеВижином малознаком, так что пардонс в случае чего.
     
    Последнее редактирование: 27 мар 2019
  14. parovoZZ

    parovoZZ Гуру

    Ну так перевел бы. Хотя бы для себя.
     
  15. b707

    b707 Гуру

    если речь о коде в первом сообщении - то скорее непонятно, почему там хоть что-нибудь работает. Там же жуть сплошная!
    Зачем вы, например, ЛАТЧ дергаете туда сюда ПОСЛЕ ввода данных?
    Код (C++):
    PORTC |= (LATCHLED2);
      _delay_ms(100);
    PORTC &= ~(LATCHLED2);