1. 背景
- 以前了解过串行通信的方法但是没有详细了解过具体实现。趁着手上有的一堆破铜烂铁尝试自己去实现一个最简单的串行控制。
目的是通过移位寄存器的不同位的表达,达到2*2=4个的继电器管断组合,达到切换矩阵的目的。
这里只记录一下程序实现,不记录硬件电路。
2. 材料
- 移位寄存器:SN74AHC594
- 固态继电器:4个
- 电源模块及外围器件,若干
- CPU1500+DQ16
3. 原理
- 选择的是一个8位移位寄存器,当响应bit等于1的时候,动作相应的继电器,组合应用。
- 移位寄存器的时钟(CLOCK)上升沿的时候会把对应的数据(DATA)状态传出(左移)。
- 8位数据传递完成后,片选信号(CS)拉高,完成一次数据传递过程。片选信号不用依靠时钟传递。
4. 程序过程
- 写入数据选择
//for 2 - 2 switch module
//1.select number
IF #IO_enable AND NOT #IO_reset THEN
#statSwitchNbr := #I_switch_nbr;
END_IF;
CASE #statSwitchNbr OF
//default
0:
#statShiftregister := 2#00000000;
//normal
10:
#statShiftregister := 2#01100010;
//cross
20:
#statShiftregister := 2#00010100;
//short
30:
#statShiftregister := 2#00000110;
//short
40:
#statShiftregister := 2#01110000;
//wire break
50:
#statShiftregister := 2#00000000;
ELSE
//others
#statShiftregister := 2#11111111;
END_CASE;
//#tmpRel := Serialize(SRC_VARIABLE := #statShiftregister, DEST_ARRAY => #statShiftArr, POS := #tmpPos);
#statShiftArr[7] := #statShiftregister.%X0;
#statShiftArr[6] := #statShiftregister.%X1;
#statShiftArr[5] := #statShiftregister.%X2;
#statShiftArr[4] := #statShiftregister.%X3;
#statShiftArr[3] := #statShiftregister.%X4;
#statShiftArr[2] := #statShiftregister.%X5;
#statShiftArr[1] := #statShiftregister.%X6;
#statShiftArr[0] := #statShiftregister.%X7;
- 时钟信号
- 按照以前做的两个定时器实现高低电平切换的方法实现了此处的时钟信号
//2. clock
#data_clock(In_switchtime := T#1000ms,
In_startAlternate := #IO_enable,
Out_switchtime_up=>#statClock_up,
Out_switchtime_Down=>#statClock_down);
- 数据写入信号
- 时钟信号的低电平半区内,等待一小段时间后写入数据(等待是为了数据写入稳定)。写入数据后,时钟信号的高电平脉冲会触发数据写进移位寄存器内。一个循环结束。
//3. shift register
#time_data(IN := #statClock_down,
PT := T#500ms);
//4. output data
IF #IO_enable AND NOT #IO_reset THEN
IF #time_data.Q AND NOT #statPulserArr[0] THEN
#O_Data := #statShiftArr[#statData_count];
#statData_count := #statData_count + 1;
END_IF;
#statPulserArr[0] := #time_data.Q;
END_IF;
- 数据发送完成后,片选信号激活
//6. output cs
#time_cs(IN:=#statClock_up,
PT:=T#100MS);
IF #statData_count > 7 AND #time_cs.Q THEN
#statCS := true;
END_IF;
#O_cs := #statCS;
- 完成数据发生,以及复位功能实现
//7. finish
#time_finish(IN:=#statCS,
PT:=t#100MS);
IF #time_finish.Q THEN
#statCS := false;
#IO_enable := false;
#IO_reset:=false;
#statData_count := 0;
RESET_TIMER(#time_data);
RESET_TIMER(#time_cs);
RESET_TIMER(#time_finish);
END_IF;
//8. reset
IF #IO_reset AND NOT #statPulserArr[2] THEN
#statSwitchNbr := 0;
#IO_enable := false;
END_IF;
#statPulserArr[2] := #IO_reset;
#time_reset(IN := #IO_reset,
PT := t#50ms,
Q => #statReset);
IF #statReset THEN
#IO_enable := true;
END_IF;
5. 整体代码如下
//for 2 - 2 switch module
//1.select number
IF #IO_enable AND NOT #IO_reset THEN
#statSwitchNbr := #I_switch_nbr;
END_IF;
CASE #statSwitchNbr OF
//default
0:
#statShiftregister := 2#00000000;
//normal
10:
#statShiftregister := 2#01100010;
//cross
20:
#statShiftregister := 2#00010100;
//short
30:
#statShiftregister := 2#00000110;
//short
40:
#statShiftregister := 2#01110000;
//wire break
50:
#statShiftregister := 2#00000000;
ELSE
//others
#statShiftregister := 2#11111111;
END_CASE;
//#tmpRel := Serialize(SRC_VARIABLE := #statShiftregister, DEST_ARRAY => #statShiftArr, POS := #tmpPos);
#statShiftArr[7] := #statShiftregister.%X0;
#statShiftArr[6] := #statShiftregister.%X1;
#statShiftArr[5] := #statShiftregister.%X2;
#statShiftArr[4] := #statShiftregister.%X3;
#statShiftArr[3] := #statShiftregister.%X4;
#statShiftArr[2] := #statShiftregister.%X5;
#statShiftArr[1] := #statShiftregister.%X6;
#statShiftArr[0] := #statShiftregister.%X7;
//2. clock
#data_clock(In_switchtime := T#1000ms,
In_startAlternate := #IO_enable,
Out_switchtime_up=>#statClock_up,
Out_switchtime_Down=>#statClock_down);
//3. shift register
#time_data(IN := #statClock_down,
PT := T#500ms);
//4. output data
IF #IO_enable AND NOT #IO_reset THEN
IF #time_data.Q AND NOT #statPulserArr[0] THEN
#O_Data := #statShiftArr[#statData_count];
#statData_count := #statData_count + 1;
END_IF;
#statPulserArr[0] := #time_data.Q;
END_IF;
//5. output clock
#O_clk := #statClock_up;
//6. output cs
#time_cs(IN:=#statClock_up,
PT:=T#100MS);
IF #statData_count > 7 AND #time_cs.Q THEN
#statCS := true;
END_IF;
#O_cs := #statCS;
//7. finish
#time_finish(IN:=#statCS,
PT:=t#100MS);
IF #time_finish.Q THEN
#statCS := false;
#IO_enable := false;
#IO_reset:=false;
#statData_count := 0;
RESET_TIMER(#time_data);
RESET_TIMER(#time_cs);
RESET_TIMER(#time_finish);
END_IF;
//8. reset
IF #IO_reset AND NOT #statPulserArr[2] THEN
#statSwitchNbr := 0;
#IO_enable := false;
END_IF;
#statPulserArr[2] := #IO_reset;
#time_reset(IN := #IO_reset,
PT := t#50ms,
Q => #statReset);
IF #statReset THEN
#IO_enable := true;
END_IF;
6. 调试过程
-
刚开始的脉冲,如图标记出来的其实是被扔掉的。程序里面一共会记录8个上升脉冲,但是标记的这一个被先进先出挤掉了。当然针对这种情况,也可以通过程序把时钟的第一个上升沿过滤掉,但是没有必要,因为这个数据本身就会被移位寄存器扔掉,移位寄存器只记录了从最后一个数据开始倒数8位数据长度。
-
按照程序的写法,此时发送的数据是
2#01100010
,所以观察的时钟的每一个上升沿,按照时间顺序应该是0->1->1->0->0->0->1->0
。
-
结束时候片选信号如下,因为enable结束的时刻把所有过程信号都清零了,所以最后一个时钟高电平很短。