Страница 1 из 1
Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 13:27:38
DJZEM
Привет.
Вот, озадачился такой, на первый взгляд, простой ерундой. Как подключить 24 релюшки к одному микроконтроллеру. Да еще и ножки микросхемы сэкономить. Конечно же 74hc595!!!
Да не тут то было. Если с двумя регистрами проблем никаких не возникало, то с тремя, что то пошло не так.
Пишу в AtmelStudio на Си.
Так я обьявляю порты
Код: Выделить всё
#define DS_PORT PORTD
#define DS_PIN 3
#define ST_CP_PORT PORTD
#define ST_CP_PIN 4
#define SH_CP_PORT PORTA
#define SH_CP_PIN 4
#define DS_low() DS_PORT&=~ (1 << DS_PIN)
#define DS_high() DS_PORT|= (1 << DS_PIN)
#define ST_CP_low() ST_CP_PORT&=~ (1 << ST_CP_PIN)
#define ST_CP_high() ST_CP_PORT|= (1 << ST_CP_PIN)
#define SH_CP_low() SH_CP_PORT&=~ (1 << SH_CP_PIN)
#define SH_CP_high() SH_CP_PORT|= (1 << SH_CP_PIN)
А это функция вывода числа через три последовательных регистра
Код: Выделить всё
void output_led_state(unsigned long int __led_state)
{
SH_CP_low();
ST_CP_low();
for (long int i=0;i<24;i++)
{
if (((1 << i) & __led_state) == (1 << i))
DS_high();
else
DS_low();
SH_CP_high();
SH_CP_low();
}
ST_CP_high();
}
А тут, в майне, я передаю число.
Код: Выделить всё
output_led_state(0b000000010000000000000000);
Но выводится только 16 бит а не 24!!!!!!
Вопрос, что я делаю не так???
В архиве схема и прошивка
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 13:37:59
AndTer
Я бы попробовал привести 1 к лонгу. Или вместо 1 использовать переменную unsigned long int
if ((((long)1 << i) & __led_state) == ((long)1 << i))
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 13:48:13
ARV
а вы бы выводили 3 байта, а не одно многобитное число... опреции с донгами ресурсоемки и неоптимальны, а с байтами как-то оно проще...
я так вообще через аппаратный SPI это делаю - скорость бешеная!
Добавлено after 3 minutes 37 seconds:
AndTer писал(а):Я бы попробовал привести 1 к лонгу. Или вместо 1 использовать переменную unsigned long int
if ((((long)1 << i) & __led_state) == ((long)1 << i))
как бы
1L куда красивше
(long)1
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 13:54:05
DJZEM
Попробовал этот код... Работает.
Но как?? Почему тот не работал? Вроде одно и то же
Аппаратный SPI, задействовать не могу, плата давно разведена и распаяна, не мною.
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 14:19:25
pyzhman
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 14:21:46
ARV
Ну, SPI и не обязательно... просто с байтами работать как-то привычнее.
А засада была в integer promotion rules, можете погуглить, да и тут писалось 100500 раз
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 14:38:03
DJZEM

Учиться еще, не переучиться.
Спасибо вам
Пойдем рисовать другую функцию дабы избавиться от
А как ни будь
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 15:17:03
ARV
заведите себе массив из нужного количества байтов, манипулируйте битами в этом массиве, как заблагорассудится, а потом функцией сбрасывайте эти байты из массива в регистры. вот так делал я (правда, у меня еще и ввод из 573-их регистров одновременно с выводом в 595-е):
Код: Выделить всё
static volatile uint8_t out_buf[BUF_OUT_SZ];
static volatile uint8_t inp_buf[BUF_INP_SZ];
// inline-функция для обмена данными с регистрами
inline static void spi_io(void){
for(uint8_t i=0; i<REGISTER_595_CNT; i++){
SPDR = out_buf[i];
while(bit_is_clear(SPSR, SPIF));
if(i < REGISTER_597_CNT)
inp_buf[i] = SPDR;
else
SPDR;
}
// импульс загрузки в регистры
PORT(REGISTER_UPDATE_PORT) &= ~_BV(REGISTER_UPDATE_PIN);
PORT(REGISTER_UPDATE_PORT) |= _BV(REGISTER_UPDATE_PIN);
}
Добавлено after 2 minutes 5 seconds:
в догонку: у вас вместо работы с аппаратным SPI будет функция вывода 1 байта там, где у меня SPDR = out_buf
;
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 18:48:39
DJZEM
Думаю разобрался в этой проблеме...
Макро
Код: Выделить всё
#define DS_PORT PORTD
#define DS_PIN 3
#define ST_CP_PORT PORTD
#define ST_CP_PIN 4
#define SH_CP_PORT PORTA
#define SH_CP_PIN 4
#define DS_low() DS_PORT&=~ (1 << DS_PIN)
#define DS_high() DS_PORT|= (1 << DS_PIN)
#define ST_CP_low() ST_CP_PORT&=~ (1 << ST_CP_PIN)
#define ST_CP_high() ST_CP_PORT|= (1 << ST_CP_PIN)
#define SH_CP_low() SH_CP_PORT&=~ (1 << SH_CP_PIN)
#define SH_CP_high() SH_CP_PORT|= (1 << SH_CP_PIN)
_Bool __o[24] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#define ON 1
#define OFF 0
#define OUT_1 __o[0]
#define OUT_2 __o[1]
#define OUT_3 __o[2]
#define OUT_4 __o[3]
#define OUT_5 __o[4]
#define OUT_6 __o[5]
#define OUT_7 __o[6]
#define OUT_8 __o[7]
#define OUT_9 __o[8]
#define OUT_10 __o[9]
#define OUT_11 __o[10]
#define OUT_12 __o[11]
#define OUT_13 __o[12]
#define OUT_14 __o[13]
#define OUT_15 __o[14]
#define OUT_16 __o[15]
#define OUT_17 __o[16]
#define OUT_18 __o[17]
#define OUT_19 __o[18]
#define OUT_20 __o[19]
#define OUT_21 __o[20]
#define OUT_22 __o[21]
#define OUT_23 __o[22]
#define OUT_24 __o[23]
Глобально обьявил для инициализации
Функции
Код: Выделить всё
void output_schift(unsigned char *data)
{
unsigned char msk,i;
for(i = 0; i < 3; i++)
{
msk = 0x80;
for(char k = 0; k < 8; k++)
{
// сравниваем каждый бит с единицей
if(data[i] & msk)
{
DS_high(); // DATA 1
SH_CP_high(); // CLK 1
SH_CP_low(); // CLK 0
}
else
{
DS_low(); // DATA 0
SH_CP_high(); // CLK 1
SH_CP_low(); // CLK 0
}
msk = msk >> 1; // сдвигаем биты
}
}
// защелкиваем регистр
ST_CP_high();
ST_CP_low();
}
void vivod()
{
s[0] = 0;s[1] = 0;s[2] = 0;
unsigned char b0 = 0,b1 = 0,b2 = 0;
b2 = __o[0]|(__o[1]<<1)|(__o[2]<<2)|(__o[3]<<3)|(__o[4]<<4)|(__o[5]<<5)|(__o[6]<<6)|(__o[7]<<7);
b1 = __o[8]|(__o[9]<<1)|(__o[10]<<2)|(__o[11]<<3)|(__o[12]<<4)|(__o[13]<<5)|(__o[14]<<6)|(__o[15]<<7);
b0 = __o[16]|(__o[17]<<1)|(__o[18]<<2)|(__o[19]<<3)|(__o[20]<<4)|(__o[21]<<5)|(__o[22]<<6)|(__o[23]<<7);
s[2] = ~b2;
s[1] = ~b1;
s[0] = ~b0;
output_schift(s);
}
void out_init()
{
s[0]=0xFF;s[1]=0xFF;s[2]=0xFF;
output_schift(s);
PORTA &= ~(1 << 3); Это тот самый оут энейбл!!!
_delay_ms(500);
}
А так обращаюсь к функциям чтобы управлять тем или иным выводом одной из трех микросхем.
Код: Выделить всё
OUT_1 = ON;
OUT_2 = OFF;
OUT_3 = ON;
OUT_15 = ON;
OUT_24 = ON;
vivod();

И самое главное, этот г**вно код работает

Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 21:43:37
ARV
вот с последним утверждением согласен полностью: говнокод эталонный!
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 21:49:49
DJZEM
Вы же сами говорили что лучше три байта отправлять в функцию вывода. Как придумал, так и написал,

Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 22:02:15
ARV
блин, ну вместо одного массива из 3 байт вы используете дополнительно массив из 24 байт, и потом страшнейшими операциями с ними манипуляции магические делаете - этого я вам не советовал! руки у вас золотые, но ведь и голову надо напрягать!
Добавлено after 7 minutes 27 seconds:
Код: Выделить всё
#define BUF_SZ 3
unsigned char buf[BUF_SZ];
void set_bit(unsigned char bit){
if(bit >= (BUF_SZ * 8)) return;
buf[bit / 8] |= 1 << (bit % 8);
}
void clr_bit(unsigned char bit){
if(bit >= (BUF_SZ * 8)) return;
buf[bit / 8] &= ~(1 << (bit % 8));
}
static void shift(unsigned char byte){
unsigned char mask;
for(mask = 1; mask; mask <<= 1){
if(byte & mask)
DS_high();
else
DS_low();
SH_CP_high();
SH_CP_low();
}
}
void shift_to_register(void){
unsigned char i;
for(i=0; i<BUF_SZ; i++)
shift(buf[i]);
}
как-то так...
Добавлено after 1 minute 32 seconds:
Код: Выделить всё
set_bit(12);
clr_bit(8);
shift_to_register();
Re: Управление 24 реле с помощью AtMega32 и 74hc595
Добавлено: Ср мар 29, 2017 22:23:44
DJZEM
Вы еще не видели как я считываю регистры ввода hc165. При чем на одной линии данных