Перейти к содержанию

Последовательная передача данных на три 74HC595


Рекомендуемые сообщения

Добрый вечер. Возникла проблема при создании монитора индикации для утройства.

post-2789-1330110410_thumb.jpg

Пока что задача вывести из масива на семисегментники цифры 0 - 8. Тоесть цифры должны отображаться постоянно. Частота смены символов 2мс.

В PROTEUSE цифры отображаются, кроме 0 - на его месте тоже 1.

На плате четко отображается только 7. Все остальные почему-то быстро изменяются и плохо отображается. Первая цифра совсем не светится.

Наверное я не правильно вывожу байты.

//=========================== Динамическая индикация =================================
void Preparation_Transmit(void){

 static unsigned char counter_2=1;

 temp_1=abcd[counter_2];
 switch(counter_2){
	case 1: {temp_2=0b00000001;break;}
	case 2: {temp_2=0b00000010;break;}
	case 3: {temp_2=0b00000100;break;}
	case 4: {temp_2=0b00001000;break;}
	case 5: {temp_2=0b00010000;break;}
	case 6: {temp_2=0b00100000;break;}
	case 7: {temp_2=0b01000000;break;}
	case 8: {temp_2=0b10000000;break;}
	case 9: {temp_2=0b00000000;temp_3++;}  
 }
	  Transmit_Indicate();
		if(counter_2 == 9)temp_3--;
		counter_2++;
		if(counter_2 == 10) counter_2=1; 

 }
 
//=========================== Пересылка байт в сдвиговый =============================
void Transmit_Indicate(void){
 Transmit_Bayt(temp_3);
  PORTC.3=1;
	  PORTC.3=0;
 Transmit_Bayt(temp_2);
  PORTC.3=1;
	  PORTC.3=0;  
 Transmit_Bayt(temp_1); 
  PORTC.3=1;
	  PORTC.3=0;
 
 PORTC.2=1;
 PORTC.2=0;
 }	   

//=========================== Загрузка бит в регистр ==================================
unsigned char Transmit_Bayt(unsigned char data){
 unsigned char di=8;
 
 while(di){
PORTC.3=1;
PORTC.1=data&0x80;
data<<=1;
PORTC.3=0;
di--;
}

 }		  


/********************************************************************************
*************/
/********************************************************************************
*************/

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{

TCNT0=0xe8;								 // Reinitialize Timer 0 value	 

Preparation_Transmit();

}

PORTC.1 - данные

PORTC.2 - защелка

PORTC.3 - строб

abcd[] - массив, содержащий коды цифр abcd[]={0x14,0x77,0x4c,0x45,0x27,0x85,0x84,0x57,0x04};

 

Исходники с файлом PROTEUS прилогаю.

Dinamo_Indicate.rar

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

Используйте SPI (если он свободен конечно) для загрузки регистров.

Например:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avrlibtypes.h>

#define F_CPU 8000000
#include <avr/delay.h>

#define SEG_A 2
#define SEG_B 8
#define SEG_C 16
#define SEG_D 128
#define SEG_E 1
#define SEG_F 4
#define SEG_G 32
#define SEG_H 64

#define DIGPORT1 PORTB
#define DIGPORT2 PORTD

#define DIG1 2
#define DIG2 1
#define DIG3 0
#define DIG4 7

#define onewirePIN 5

u08 dig_trf1=0,dig_trf2=0,dig_trf3=0,dig_trf4=0;
volatile u08 refresh_count=0;
u08 temp_flg=0;
volatile long temperature=0;


ISR(TIMER0_OVF_vect) {
 
 static char upd_dig=1;
 unsigned char to_transfer=0;  
 
 DIGPORT1 &= ~(1<<DIG1);
 DIGPORT1 &= ~(1<<DIG2); 
 DIGPORT1 &= ~(1<<DIG3); 
 DIGPORT2 &= ~(1<<DIG4); 

 if (upd_dig==1) {
  to_transfer=dig_trf1;
  DIGPORT1|=1<<DIG1;
  upd_dig=2;
 } else if (upd_dig==2) {
  to_transfer=dig_trf2;
  DIGPORT1|=1<<DIG2;
  upd_dig=3;
 } else if (upd_dig==3) {
  to_transfer=dig_trf3;
  DIGPORT1|=1<<DIG3;
  upd_dig=4;
 } else if (upd_dig==4) {
  to_transfer=dig_trf4;
  DIGPORT2|=1<<DIG4;
  upd_dig=1;
 }

 SPDR = to_transfer;
 while( !(SPSR & (1<<SPIF)) ) {;}	 
  
 refresh_count++;
 wdt_reset();
 
}

unsigned char present_ds18b20(void){ 
unsigned char res;
 DDRC|= 1<<onewirePIN;	   
 _delay_loop_2(950); 
 
 DDRC&=~(1<<onewirePIN);		  
 _delay_loop_2(130);		 

 if ((PINC&(1<<onewirePIN))==0x00) res=1;  
 else res=0;  
 
_delay_loop_2(810); 
  
return res;
}

void send_ds18b20(unsigned char command){ 
unsigned char i, data;

data=command;

for(i=0;i<8;i++)
{
 if ((data&0x01)==0x01) {			   
DDRC|= 1<<onewirePIN; 
_delay_loop_2(4);		
DDRC&=~(1<<onewirePIN); 
_delay_loop_2(120);	
 } else {				   	
DDRC|= 1<<onewirePIN; 
_delay_loop_2(110);  
DDRC&=~(1<<onewirePIN); 
_delay_loop_2(4);
 }
 data=data>>1;
}

}

void receive_ds18b20(void){ 
unsigned char i;
temperature=0;
temp_flg=0;

for(i=0;i<12;i++) {
 
 DDRC|= 1<<onewirePIN; 
 _delay_loop_2(4);	   
 DDRC&=~(1<<onewirePIN); 
 _delay_loop_1(12);	   

 if ((PINC&(1<<onewirePIN))==0x00) temperature&=~(1<<i); 
 else { temperature|=1<<i;}		   														 
 _delay_loop_2(100);	 											
}

}

int init_mk(void){

PORTB=0x00;
DDRB=0x2F;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x80;

TCCR0B= _BV(CS01) | _BV(CS00);

TIMSK0= _BV(TOIE0);

SPCR=_BV(SPE) | _BV(MSTR);

wdt_enable(WDTO_60MS);

sei();
}

u08 NumToByte( u08 num, u08 dot )
{
u08 byte = 0;
switch(num)
{
  case 0: byte = SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F; break;
  case 1: byte = SEG_B + SEG_C; break;
  case 2: byte = SEG_A + SEG_B + SEG_G + SEG_E + SEG_D; break;
  case 3: byte = SEG_A + SEG_B + SEG_C + SEG_D + SEG_G; break;
  case 4: byte = SEG_G + SEG_B + SEG_C + SEG_F; break;
  case 5: byte = SEG_A + SEG_F + SEG_C + SEG_D + SEG_G; break;
  case 6: byte = SEG_A + SEG_G + SEG_C + SEG_D + SEG_E + SEG_F; break;
  case 7: byte = SEG_A + SEG_B + SEG_C; break;
  case 8: byte = SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G; break;
  case 9: byte = SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G; break;

  case '-': byte = SEG_G; break;
  }

if ( dot ) byte |= SEG_H;

return byte;
}

void NumToDig( u32 num, u08 *digit1, u08 *digit2, u08 *digit3, u08 *digit4)
{
*digit1 = 0;
*digit2 = 0;
*digit3 = 0;  
*digit4 = 0;
if ( num > 9999 ) return;

while ( num > 999 ) { num -= 1000; (*digit1)++; }
while ( num > 99 ) { num -= 100; (*digit2)++; }
while ( num > 9 )  { num -= 10;  (*digit3)++; }
*digit4 = num;
}

void measure() {
if (present_ds18b20()) {
send_ds18b20(0xCC);
send_ds18b20(0x44);

while(!(PINC&(1<<onewirePIN)));

  present_ds18b20();
send_ds18b20(0xCC);
send_ds18b20(0xBE);
receive_ds18b20();

}
}

void display(){

 if (temperature>3000) { temperature=4096-temperature; temp_flg=1;}
  	
 temperature=(temperature*625)/100;

if (temp_flg) {  
  if (temperature<1000) {
NumToDig(temperature,&dig_trf1,&dig_trf2,&dig_trf3,&dig_trf4);  
 
dig_trf1=NumToByte('-',0);  
dig_trf2=NumToByte(dig_trf2,1);
dig_trf3=NumToByte(dig_trf3,0);
dig_trf4=NumToByte(dig_trf4,0);  
 } else {
temperature/=10; 
  
NumToDig(temperature,&dig_trf1,&dig_trf2,&dig_trf3,&dig_trf4);  
 
dig_trf1=NumToByte('-',0);  
dig_trf2=NumToByte(dig_trf2,0);
dig_trf3=NumToByte(dig_trf3,1);
dig_trf4=NumToByte(dig_trf4,0);
 }  
} else if (temperature>=10000) {
 temperature/=10; 
 NumToDig(temperature,&dig_trf1,&dig_trf2,&dig_trf3,&dig_trf4); 
 
 dig_trf1=NumToByte(dig_trf1,0);  
 dig_trf2=NumToByte(dig_trf2,0);
 dig_trf3=NumToByte(dig_trf3,1);
 dig_trf4=NumToByte(dig_trf4,0);
} else if (temperature<1000) {
 NumToDig(temperature,&dig_trf1,&dig_trf2,&dig_trf3,&dig_trf4); 
 
 dig_trf1=0; 
 dig_trf2=NumToByte(dig_trf2,1);
 dig_trf3=NumToByte(dig_trf3,0);
 dig_trf4=NumToByte(dig_trf4,0);
} else {  
 NumToDig(temperature,&dig_trf1,&dig_trf2,&dig_trf3,&dig_trf4);
 
 dig_trf1=NumToByte(dig_trf1,0);
 dig_trf2=NumToByte(dig_trf2,1);
 dig_trf3=NumToByte(dig_trf3,0);
 dig_trf4=NumToByte(dig_trf4,0);
}
}

void main(void){

init_mk();  

while(1){
 
 wdt_reset();

 if  ( refresh_count > 200 ) {  
  measure();
  display();	   
  refresh_count=0;
 } 
 
}

}

Динамическая индикация, на 4 сегмента 1 сдвиговый (74hc164). После загрузки данных в ваши регистры просто добавить защелку. Может чем то поможет.

Очень тяжело читать Ваш код с "магическими числами".

Ссылка на комментарий
Поделиться на другие сайты

Очень тяжело читать Ваш код с "магическими числами".

Наверное потому, что я пишу в CodeVisionAVR, а вы в WinAVR. Поверьте, ваши числа для меня имеют не меньше "магии".

Ссылка на комментарий
Поделиться на другие сайты

Наверное потому, что я пишу в CodeVisionAVR, а вы в WinAVR. Поверьте, ваши числа для меня имеют не меньше "магии".

я про

TCNT0=0xe8;

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

Ссылка на комментарий
Поделиться на другие сайты

Позвольте вставить свои замечания.

 

1. В протеусе эта схема работает, однако в реальной схеме нужны резисторы в цепи каждого диода-сегмента.

 

2. Максимальный ток каждого вывода 74HC595 - 20мА, при условии, что общее потребление должно быть не больше 70мА. Итого каждый сегмент должен потреблять не более 2.5мА (2.5*8=20).

Если нужно больше - то найдите аналог от Texas Instruments - TPIC6B595. Либо последовательно добавить еще ULN2003/2803, но это подойдет только для индикаторов с общим анодом.

 

3. Примерный алгоритм должет быть такой - загоняем в регистры последовательно 24 бита данных, предварительно правильно расчитанных (сначала, как я понимаю, биты общих анодов/катодор (разрядов), и в конце - сегменты). Затем дергаем вывод защелки - для передачи этих самых данных на выход регистра. И так по кругу.

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

Для публикации сообщений создайте учётную запись или авторизуйтесь

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

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...