Страница 1 из 1
Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Вс дек 13, 2020 23:11:51
AlexCrazy
Доброго времени суток, радиолюбители и профессионалы. У меня небольшая проблемка, а именно непонимание некоторых функций сдвигового регистра модели SN74HC595N.
К сообщению прикреплён pdf даташит на Английском языке. В нём описаны такие непонятные мне функции, как SRCLK и RCLK.
Хоть в английском не полный дурак, но не пойму при чём тут часы, а если это тактовая частота, то при чём тут она?
Объясните неучу, пожалуйста.
P.S. не уверен что создал тему в нужном разделе, админ извини, если что.

картинка
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн дек 14, 2020 14:09:45
Meteor
По сигналу SRCLK данные записываются в "первый регистр" (сдвигаются), по сигналу RCLK принятые в "первый регистр" данные перезаписываются в выходной регистр и если разрешен вывод, то эти данные появляются на шине вне микросхемы
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн дек 14, 2020 15:50:18
AlexCrazy
[uquote="Meteor",url="/forum/viewtopic.php?p=3941479#p3941479"]По сигналу SRCLK данные записываются в "первый регистр" (сдвигаются), по сигналу RCLK принятые в "первый регистр" данные перезаписываются в выходной регистр и если разрешен вывод, то эти данные появляются на шине вне микросхемы[/uquote]
Тоесть это просто спец. функции, и для того чтобы просто писать данные в сдвиговый регистр последовательно, со стандартным сдвигом, можно просто подавать сигналы на SER, а RCLK и SRCLK просто не трогать? Я правильно понял?
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн дек 14, 2020 16:24:22
АлександрЛ
[uquote="AlexCrazy",url="/forum/viewtopic.php?p=3941550#p3941550"]Тоесть это просто спец. функции, и для того чтобы просто писать данные в сдвиговый регистр последовательно, со стандартным сдвигом, можно просто подавать сигналы на SER, а RCLK и SRCLK просто не трогать? Я правильно понял?[/uquote]
Нет, неправильно.. Это УПРАВЛЕНИЕ РЕГИСТРОМ
Вот таблица:
Спойлер

Какой- то у вас даташит странный..

Хотя в чипдипе он же..
Вот тут:
https://www.rlocman.ru/shem/schematics.html?di=65110
вроде неплохо описана работа этого регистра
SRCLK передвигает данные, поступающие на вход регистра (SER) по каждому "клоку" на один шаг, а RCLK передаёт данные (в том состоянии, в котором они находятся на этот момент времени) из самого регистра на выходы.
Если вы умеете пользоваться протеусом, то там можно посмотреть, что происходит с регистром в "типа ручном управлении"..

Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн дек 14, 2020 16:51:33
КРАМ
[uquote="AlexCrazy",url="/forum/viewtopic.php?p=3941550#p3941550"]То есть это просто спец. функции[/uquote]
Любой SPI в общем случае имеет ЧЕТЫРЕ сигнала. Два - это данные (входные и выходные). Один - клоки мастера (сдвигающее тактирование). И еще один - чип селект. Последний сигнал не препятствует сдвигу. Он перезаписывает ПО ЗАДНЕМУ фронту данные из сдвигового регистра на выход или в исполнительный регистр микросхемы-слейва SPI шины. Без перезаписи данные просто будут проталкиваться на выход самого SPI клоками мастера.
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн дек 14, 2020 17:30:04
AlexCrazy
Благодарю, ознакомлюсь. Дело в том, что мне нужно с микроконтроллера посылать байт информации на сдвиговый регистр, откуда сигналы пойдут на сборку дарлингтона для включения нужных сегментов ВЛИ. Вот и пытаюсь понять куда байты загружать... Тоесть без перезаписи данные просто будут заменятся новыми? Если так, то так и нужно!
Добавлено after 10 minutes 59 seconds:
ПОНЯЛ! Это что-то вроде "Защёлки"(RCLK) а SRCLK это передвигает данные?
Код: Выделить всё
// отправляем в цикле по два байта в сдвиговые регистры
for(byte i = 0; i <= 3; i++){
digitalWrite(RCLK, LOW); // открываем защелку
shiftOut(DIO, SCLK, MSBFIRST, digit[digitBuffer[i]]); // отправляем байт с "числом"
shiftOut(DIO, SCLK, MSBFIRST, chr[i]); // включаем разряд
digitalWrite(RCLK, HIGH); // защелкиваем регистры
delay(1); // ждем немного перед отправкой следующего "числа"
}
}
Добавлено after 13 minutes 14 seconds:
Meteor,
КРАМ,
АлександрЛ, Спасибо огромное! С наступающим!
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн янв 11, 2021 20:28:31
Эйлер Леонард
Доброго времени суток.
Есть неплохая библиотека для работы со сдвиговым регистром 74HC595
shiftreg.cpp
Спойлер
/****************************************************************************
* File Name : shiftreg.c
* Author : D.Gotic
* Version : V0.1
* Date : 03/12/2010
* Description : This file contains all the functions definitions
* for the 74HC595 shit register driver
*****************************************************************************/
/* Includes ----------------------------------------------------------------*/
#include "shiftreg.h"
#include "macros.h"
#define BIT_MASK 0x80
/* Private macros-----------------------------------------------------------*/
/* Private functions -------------------------------------------------------*/
#define shift_in_pulse(port,reg_pin) sbi(port,reg_pin); cbi(port,reg_pin)
#define parallel_out_pulse(port,reg_pin) sbi(port,reg_pin); cbi(port,reg_pin)
//
// Function Name : SHIFTREG_InitRegister
// Description : Initializes the interface from the uC to the shift register
// Input : DDR adress and PORT adress of the interface and pin numbers
// of the uC interface
// Return : initialized register structure
//
SHIFTREG_register SHIFTREG_InitRegister(
volatile uint8_t *ddr_addr,
volatile uint8_t *port_addr,
uint8_t ds_pin,
uint8_t st_cp_pin,
uint8_t sh_cp_pin) {
SHIFTREG_register tmp_reg;
tmp_reg.DDR_addr = ddr_addr;
tmp_reg.PORT_addr = port_addr;
tmp_reg.DS_pin = ds_pin;
tmp_reg.ST_CP_pin = st_cp_pin;
tmp_reg.SH_CP_pin = sh_cp_pin;
sbi(*(tmp_reg.DDR_addr),tmp_reg.DS_pin);
sbi(*(tmp_reg.DDR_addr),tmp_reg.ST_CP_pin);
sbi(*(tmp_reg.DDR_addr),tmp_reg.SH_CP_pin);
return tmp_reg;
}
/****************************************************
* Function Name : SHIFTREG_OutputValue
* Description : Transmits nbytes bytes to nbytes shift registers and outputs the values
* Input : shift register structure, bytes to transmit, number of bytes to transmit
* Return : None
******************************************************/
void SHIFTREG_OutputValue(SHIFTREG_register *reg, uint8_t *bytes, uint8_t nbytes ){
uint8_t mask, i, j;
for (i=0; i<nbytes; i++) {
mask = BIT_MASK;
for (j = 0; j< 8; j++) {
/* mask bit
* if bit 0 output 0
* else output 1
* shift bit mask one place right (сдвинуть битовую маску на одно место вправо) */
if (bytes & mask){ //сравниваем каждый бит с единицей
sbi(*(reg->PORT_addr),reg->DS_pin);
shift_in_pulse(*(reg->PORT_addr),reg->SH_CP_pin); }
else{
cbi(*(reg->PORT_addr),reg->DS_pin);
shift_in_pulse(*(reg->PORT_addr),reg->SH_CP_pin); }
mask = (mask >> 1); //сдвигаем биты
}
}
parallel_out_pulse(*(reg->PORT_addr),reg->ST_CP_pin);
}
/***********************END OF FILE***********************/ shiftreg.hСпойлер
/******************************************************************************
* File Name : shiftreg.h
* Author : D.Gotic
* Version : V0.1
* Date : 03/12/2010
* Description : This file contains all the functions prototypes
* and structure definitions for the 74HC595 shit register driver
******************************************************************************/
/* Define to prevent recursive inclusion ------------------------------------*/
#ifndef SHIFTREG_H
#define SHIFTREG_H
/* Includes ------------------------------------------------------------------*/
#include <inttypes.h>
/* a structure which defines the interface from the uC to the SHIFT REGISTER */
typedef struct _SHIFTREG_register {
volatile uint8_t *DDR_addr; /* address of the uC Data Direction Register */
volatile uint8_t *PORT_addr; /* address of the uC PORT Register */
uint8_t DS_pin; /* Pin number to which the DS pin is connected */
uint8_t ST_CP_pin; /* Pin number to which the ST_CP pin is connected */
uint8_t SH_CP_pin; /* Pin number to which the SH_CP pin is connected */
} SHIFTREG_register;
/* Function prototypes -----------------------------------------------------------*/
SHIFTREG_register SHIFTREG_InitRegister(
volatile uint8_t *ddr_addr,
volatile uint8_t *port_addr,
uint8_t ds_pin,
uint8_t st_cp_pin,
uint8_t sh_cp_pin
);
void SHIFTREG_OutputValue(
SHIFTREG_register *reg,
uint8_t *bytes,
uint8_t nbytes);
#endif /* SHIFTREG_H */
/************************** END OF FILE **************************/ macros.hСпойлер
/*************************************************************************
* File Name : shiftreg.h
* Author : D.Gotic
* Version : V0.1
* Date : 03/12/2010
* Description : Helper macros for setting and clearing a bit in a register
* Вспомогательные макросы для установки и очистки битов в регистре
**************************************************************************/
#ifndef MACROS_H
#define MACROS_H
#define cbi(addr,bit) addr &= ~(1 << bit)
#define sbi(addr,bit) addr |= (1 << bit)
#endif /* MACROS_H */
/****************************END OF FILE**********************************/ main.cppСпойлер
/* --------- ATiny85 --------- */
#define F_CPU 8000000UL //частота процессора 8 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#include <util/delay.h>
#include <avr/wdt.h>
#include "shiftreg.h"
#include "Interruptions.h"
#include "levelRange.h"
#include "macros.h"
volatile uint8_t tt = 0b00000000;
volatile uint8_t code = 0b00000000;
volatile uint8_t level = 0;
volatile uint8_t j = 0;
volatile uint32_t impulses = 0;
volatile uint32_t average = 0;
volatile uint32_t m[] = { 0,0,0,0,0 };
volatile uint8_t k = 0;
volatile uint8_t lev[16][4] = {// коды цифр для индикатора в зависимости от уровня (0...15)
{ 0b00111111/*0*/,0b10111111/*0.*/,0b00111111/*0*/,0b00010111 },// 0
{ 0b01111111/*8*/,0b10111111/*0.*/,0b00111111/*0*/,0b00110111 },// 1
{ 0b01111101/*6*/,0b10000110/*1.*/,0b00111111/*0*/,0b01110111 },// 2
{ 0b01100110/*4*/,0b11011011/*2.*/,0b00111111/*0*/,0b11110111 },// 3
{ 0b01011011/*2*/,0b11001111/*3.*/,0b00111111/*0*/,0b11110111 },// 4 ---
{ 0b00111111/*0*/,0b11100110/*4.*/,0b00111111/*0*/,0b11110111 },// 5 ---
{ 0b01111111/*8*/,0b11100110/*4.*/,0b00111111/*0*/,0b11110111 },// 6 ---
{ 0b01111101/*6*/,0b11101101/*5.*/,0b00111111/*0*/,0b11110011 },// 7
{ 0b01100110/*4*/,0b11111101/*6.*/,0b00111111/*0*/,0b11110011 },// 8 ---
{ 0b01011011/*2*/,0b10000111/*7.*/,0b00111111/*0*/,0b11110011 },// 9 ---
{ 0b00111111/*0*/,0b11111111/*8.*/,0b00111111/*0*/,0b11110011 },//10 ---
{ 0b01111111/*8*/,0b11111111/*8.*/,0b00111111/*0*/,0b11110001 },//11
{ 0b01111101/*6*/,0b11101111/*9.*/,0b00111111/*0*/,0b11110001 },//12 ---
{ 0b01100110/*4*/,0b10111111/*0.*/,0b00000110/*1*/,0b11110001 },//13 ---
{ 0b01011011/*2*/,0b10000110/*1.*/,0b00000110/*1*/,0b11110001 },//14 ---
{ 0b00111111/*0*/,0b11011011/*2.*/,0b00000110/*1*/,0b11110000 } //15
};
/*
0 (00.0)
1 (00.
2 (01.6)
3 (02.4)
4 (03.2)
5 (04.0)
6 (04.
7 (05.6)
8 (06.4)
9 (07.2)
10 (08.0)
11 (08.
12 (09.6)
13 (10.4)
14 (11.2)
15 (12.0)
*/
/*
uint8_t digits1[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x00
};
*/
uint8_t digits[] = {
0b00111111,/*0*/
0b00000110,/*1*/
0b01011011,/*2*/
0b01001111,/*3*/
0b01100110,/*4*/
0b01101101,/*5*/
0b01111101,/*6*/
0b00000111,/*7*/
0b01111111,/*8*/
0b01101111,/*9*/
0b00000000/*пусто*/
};
//0b00111000, /*L*/
//0b00011000 /*L min*/
struct Array {
uint8_t g[5]; // 0,1,2,3 - хранение кодов разрядов чисел, 4 - коды для матрицы
} num;
Array SplitNumber( uint16_t n ){
Array array;
for( uint8_t i = 0; i < 4; i++ ){
array.g = digits[n % 10];
n /= 10; }
return array;
};
SHIFTREG_register reg;
ISR(INT0_vect){ impulses++; };
ISR(TIM0_COMPA_vect){
//num.g[4] = segments( level, (tt=~tt) );
//num.g[3] = digits[11];
//SHIFTREG_OutputValue( ®, num.g, 5 );
};
ISR(TIM0_COMPB_vect){
//num = SplitNumber(number);
//SHIFTREG_OutputValue( ®, num.g, 4 );
//number = 0;
};
ISR(TIM1_COMPA_vect){
//num = SplitNumber(impulses);
//SHIFTREG_OutputValue( ®, num.g, 4 );
};
ISR(TIM1_COMPB_vect){
//num = SplitNumber(impulses);
//SHIFTREG_OutputValue( ®, num.g, 4 );
//impulses = 0;
};
ISR(WDT_vect){
j=(j>2)?(j=0):(j+1);
average = average+impulses;
impulses=0;
if(j==3){
num = SplitNumber(average);//average
SHIFTREG_OutputValue( ®, num.g, 4 );
average=0;
}
};
int main(void){
reg = SHIFTREG_InitRegister(&DDRB, &PORTB, PB0/*ds_pin*/,PB1/*st_cp_pin*/,PB3/*sh_cp_pin*/);
INT0_init();
//TimerCounter_0();
WDT_init();
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK = (1<<OCIE1A) | (1<<OCIE1B) | (1<<OCIE0A) | (1<<OCIE0B) | (0<<TOIE1) | (0<<TOIE0);
sei();
while (1) { }
};
/*
0 00000000
1 00000001 (1<<0)
2 = 00000010 (1<<1)|(1<<0)
3 00000011 (1<<0)
0 = 00000000 (1<<1)|(1<<0)
1 00000001 (1<<0)
2 = 00000010 (1<<1)|(1<<0)
3 00000011 (1<<0)
lev[4][3]^=((1<<7)|(1<<6)|(1<<5)|(1<<2));
*/ Собрал схемку в протеусе, проверил, работает. Это просто счетчик импульсов на ATiny85 с выводом значений на семисегментные индикаторы.
Мой проект в рамках самообразования (код черновик).
Но я решил пойти несколько дальше, т.к. непосредственно на 74HC595 много
не подключить, по току есть ограничения. Конечно выручит ULN2803A.
https://www.chipdip.ru/product/uln2803a-stm
Матрица из восьми транзисторов Дарлингтона, 500мА, 50В.
Однако есть сдвиговые регистры уже с силовыми ключами - TPIC6C595N напр.
Описаний его и поделок, тем более библиотек - не много, и то все ардуиновские.
С ардуино особо не дружу - предпочитаю чистый C/C++ и голый МК.
http://labdegaragem.com/forum/topics/pl ... t%3A644315
У меня есть намерение что-нибудь сделать на этом регистре. Ну там бегущие поворотники, да мало ли чего.
Наброски кода уже есть, но вот в протеусе подходящей модели не нашел. Начал лепить
этот регистр из примитивов. И на этом дело остановилось. Может быть кто подскажет
чем можно заменить TPIC6C595N в протеусе или как синтезировать сей девайс.
(Здесь Datasheet на TPIC6C595N)
https://www.chipdip.ru/product/tpic6c595n
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Пн янв 11, 2021 23:13:31
АлександрЛ
Если сравнить эти микросхемы (74HC595 и TPIC6C595) в представлении стандарта " IEC logic symbol" то "функционально" они одинаковы, и, скорее всего, для TPIC6C595 можно попробовать использовать библиотеку для 74HC595 , а в протеусе просто поставить 74HC595..

С учётом того, что у них нумерация выводов не совпадает..
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Вт янв 12, 2021 04:08:29
musor
если ТС работать с ВЛИ то пока не позно меняй регистр на sn75518

тогда тебеж не нужны будут ВВ ключи
все равно код ПОКА не написан пиши сразу под него
Добавлено after 4 minutes 36 seconds:
strobe там заточен на АРЯ можно не применять подаф 0
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Вс янв 17, 2021 16:56:23
Эйлер Леонард
Здравствуйте уважаемые коты. Коли здесь упоминается о сдвиговом регистре 74HC595, то за вечерок (дело было вечером - делать было нечего) я написал некоторую реализацию его применения в связке с матрицей из восьми транзисторов Дарлингтона - ULN2803A. Среда разработки AtmelStudio, MCU Attiny13. Назвал это дело "Веселый стоп-сигнал" и "Веселый поворотник". Может быть себе на мотоцикл приколхозю. Код на Си. Дополнительно решил разобраться как правильно укладывать микроконтроллер спать и как его будить. Электроэнергию надо экономить. Для "помигать светодиодами" счел целесообразным снизить частоту до 128 kHz, ну и поиграть с единственным таймером на Attiny13. Это регистры OCR0A/TCCR0B (Output Compare Register и Timer/Counter Control Register). Просимулировал в протеусе - вроде как фурычит.
Стоп-сигналСпойлер
Код: Выделить всё
/* ATtiny13 + ( 74HC595 + ULN2803 )
Весёлый стоп-сигнал
*/
#define F_CPU 128000UL // 128 kHz clock speed
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/io.h>
#define DATA_PORT PORTB
#define DATA_DDR DDRB
#define DATA PB0 // Data pin (DS) pin location
#define CLOCK PB2 // Shift Clock (SH_CP) pin location
#define LATCH PB3 // Store Clock (ST_CP) pin location
#define BUTTON PB1 //
#define HC595DataHigh() ( DATA_PORT |= (1<<DATA) )
#define HC595DataLow() ( DATA_PORT &=(~(1<<DATA)) )
volatile uint8_t k = 0;
const uint8_t led_pattern[9] = {
0b11111111,
0b11111110,
0b11111100,
0b11111000,
0b11110000,
0b11100000,
0b11000000,
0b10000000,
0b00000000
};
//-------
void HC595Pulse(void){ // Pulse the Shift Clock
DATA_PORT |= (1<<CLOCK); // HIGH
DATA_PORT &=(~(1<<CLOCK)); // LOW
}
//-------
void HC595Latch(void){ // Pulse the Store Clock
DATA_PORT |=( 1<<LATCH ); // HIGH
_delay_ms(1);
DATA_PORT&=(~(1<<LATCH)); // LOW
_delay_ms(1);
}
//-------
void HC595Write(uint8_t data){
//Последовательная отправка каждые 8 бит
//Send each 8 bits serially
//Order is MSB first
for( uint8_t i=0; i<8; i++ ){
//Output the data on DS line according to the Value of MSB
if(data & 0b10000000) { HC595DataHigh();} //MSB is 1 so output high
else { HC595DataLow(); } //MSB is 0 so output high
HC595Pulse(); //Pulse the Clock line
data = (data<<1); //Now bring next bit at MSB position
}
//Now all 8 bits have been transferred to shift register
//Move them to output latch at one
HC595Latch();
}
//-------
void HC595Init(void){ // Initialize HC595
// Make the Data(DS), Shift clock (SH_CP), Store Clock (ST_CP) lines output
DATA_DDR|=((1<<DATA)|(1<<CLOCK)|(1<<LATCH));
HC595Write(0b00000000);
}
/* Настройка таймера */
void setupTimer0(void){
TCCR0A = TCCR0B = TCNT0 = 0;// Clear registers
OCR0A = 4;// 25 Hz (128000/((4+1)*1024))
TCCR0A |= (1 << WGM01);// CTC
//TCCR0B |= (1 << CS02) | (1 << CS00);// Prescaler 1024, перенесено в прерывания
TIMSK0 |= (1 << OCIE0A);// Output Compare Match A Interrupt Enable
}
/* Настраиваемое прерывание _П_П_П_П_П_П_ */
void setupINT0(void){
GIMSK |= (1<<INT0);
MCUCR |= (1<<ISC00); // Любое логическое изменение на INT0 генерирует запрос прерывания.
}
/* Таймер, CTC режим */
ISR( TIM0_COMPA_vect ){
k=(k>9) ? (k=0) : (k+1);
if( !(PINB & (1<<BUTTON)) ) {// Кнопка нажата
sleep_disable();// Проснуться
HC595Write( led_pattern[9-k] ); }
else { HC595Write( led_pattern[k] ); } // Кнопка отпущена
if( k==9 ){
TCCR0B = 0; // Останавливаем таймер
sleep_cpu(); // Спать!
}
}
/* Обработчик прерывания INT0 */
ISR( INT0_vect ){
TCCR0B |= (1 << CS02) | (1 << CS00);// Запускаем таймер
if( PINB & (1<<BUTTON) ){// Кнопка отпущена
k=0;
}
}
//-------
int main(void){
cli();
HC595Init();
setupINT0();
setupTimer0();
DDRB &= ~(1<<BUTTON); // вход
PORTB |= (1<<BUTTON); // подтянут
/* Отключаем не используемые функции, для экономии электроэнергии */
ADCSRA &= ~(1<<ADEN); //Disable ADC
ACSR = (1<<ACD); //Disable the analog comparator
/* Подготовка ко сну */
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set Sleep Mode: Power Down
sleep_enable(); // Enable Sleep Mode
sei();
while(1){ /* */ }
}
Сигнал поворотникаСпойлер
Код: Выделить всё
/* ATtiny13 + ( 74HC595 + ULN2803 )
Весёлый сигнал поворотника
*/
#define F_CPU 128000UL // 128 kHz clock speed
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h> // Режимы сна
#define DATA_PORT PORTB
#define DATA_DDR DDRB
#define DATA PB2 // Data pin (DS) pin location
#define CLOCK PB0 // Shift Clock (SH_CP) pin location
#define LATCH PB3 // Store Clock (ST_CP) pin location
#define BUTTON PB4 //
#define HC595DataHigh() ( DATA_PORT |= (1<<DATA) )
#define HC595DataLow() ( DATA_PORT &=(~(1<<DATA)) )
volatile uint8_t k = 0;
const uint8_t led_pattern[9] = {
0b11111111, // 255
0b11111110, // 254
0b11111100, // 252
0b11111000, // 248
0b11110000, // 240
0b11100000, // 224
0b11000000, // 192
0b10000000, // 128
0b00000000 // 0
};
//-------
void HC595Pulse(void){ // Pulse the Shift Clock
DATA_PORT |= (1<<CLOCK); // HIGH
DATA_PORT &=(~(1<<CLOCK)); // LOW
}
//-------
void HC595Latch(void){ // Pulse the Store Clock
DATA_PORT |=( 1<<LATCH ); // HIGH
_delay_ms(1);
DATA_PORT&=(~(1<<LATCH)); // LOW
_delay_ms(1);
}
//-------
void HC595Write(uint8_t data){
//Последовательная отправка каждые 8 бит
//Send each 8 bits serially
//Order is MSB first
for( uint8_t i=0; i<8; i++ ){
//Output the data on DS line according to the Value of MSB
if(data & 0b10000000) { HC595DataHigh();} //MSB is 1 so output high
else { HC595DataLow(); } //MSB is 0 so output high
HC595Pulse(); //Pulse the Clock line
data = (data<<1); //Now bring next bit at MSB position
}
//Now all 8 bits have been transferred to shift register
//Move them to output latch at one
HC595Latch();
}
/* Initialize HC595 */
void HC595Init(void){
// Make the Data(DS), Shift clock (SH_CP), Store Clock (ST_CP) lines output
DATA_DDR|=((1<<DATA)|(1<<CLOCK)|(1<<LATCH));
HC595Write(0b00000000);
}
/* Не настраиваемое прерывание _П_П_П_П_П_П_ по любому фронту */
void setupPCINT0(void){
GIMSK |= (1<<PCIE); // Разрешаем внешние прерывания PCINT0.
PCMSK |= (1<<BUTTON); // Разрешаем по маске прерывания.
}
/* Настройка таймера */
void setupTimer0(void){
TCCR0A = TCCR0B = TCNT0 = 0; // Clear registers
OCR0A = 4; // 25 Hz (128000/((4+1)*1024))
TCCR0A |= (1 << WGM01); // CTC
//TCCR0B |= (1 << CS02) | (1 << CS00); // Prescaler 1024, перенесено в прерывания
TIMSK0 |= (1 << OCIE0A); // Output Compare Match A Interrupt Enable
}
/* Обработчик прерывания PCINT0 */
ISR( PCINT0_vect ){
// Кнопка нажата
if( !(PINB & (1<<BUTTON)) ){
// Проснуться
sleep_disable();
// Запускаем таймер
TCCR0B |= (1 << CS02) | (1 << CS00);
} else { // Кнопка отпущена
// Останавливаем таймер
TCCR0B = 0;
HC595Write(0b00000000);
k = 0;
sleep_cpu(); // Спать!
}
}
/* Таймер, CTC режим */
ISR( TIM0_COMPA_vect ){
k=( (k>9) ? (k=0) : (k+1) );
if( k < 10 ){
HC595Write( led_pattern[9-k] );
}
}
int main(void){
cli();
HC595Init();
setupPCINT0();
setupTimer0();
PORTB|= (1 << BUTTON); //Устанавливаем pull-up режим ножки BUTTON
DDRB &= ~(1 << BUTTON); //Настраиваем ножку BUTTON в режим входа
/* Отключаем не используемые функции, для экономии электроэнергии */
ADCSRA &= ~(1<<ADEN); //Disable ADC
ACSR = (1<<ACD); //Disable the analog comparator
/* Подготовка ко сну */
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set Sleep Mode: Power Down
sleep_enable(); // Enable Sleep Mode
sei(); // разрешаем прерывания
while(1){ /* здесь делать нечего */ }
}
Отличие одного кода от другого лишь в логике организации беготни светодиодных огоньков. Кроме того, функции сдвигового регистра не предусматривают возможности каскадирования.
Re: Непонятные функции сдвигового регистра SN74HC595N
Добавлено: Сб янв 23, 2021 15:25:20
VladislavS
Эйлер Леонард, зачем такие адские задержки? Тинька 595-й по скорости не "пробьёт". И вот такой алгоритм будет компактней и быстрей. Для тиньки это актуально.
Код: Выделить всё
void HC595Write(uint8_t data)
{
for (uint8_t mask=0x80; mask; )
{
if(data & mask) DATA=1; else DATA=0;
mask>>=1;
CLK=1; CLK=0;
}
LE=1;
LE=0;
}