Иван Денисов писал(а):
Свой код бортового и управляющего модулей прилагаю к сообщению.
Упростил твою бортовую программу:
- выделил таймер в отдельный модуль
- задействовал модуль MemFormatters для того, чтобы избавиться от SYSTEM.GET в Receive
- задействовал модуль PinCfg для настройки ножки микроконтроллера
- убрал дублирование кода
- упростил логику работы светодиода
Код:
MODULE IvanTestDAC1;
IMPORT SYSTEM, ARMv7M := MicroARMv7M, MF := MicroMemFormatters,
MCU := MicroSTM32F405, PinCfg := MicroSTM32F405PinCfg,
Sys := MicroSTM32F405System, TP3 := MicroSTM32F405TrimblePort3,
PeriodicTimer := IvanSysTick0;
CONST
periodicTimerFreq = 1024; (* Hz *)
nChannels = 2;
VAR
cnt0: INTEGER;
both: BOOLEAN;
channels: ARRAY nChannels OF RECORD
timeDAC: INTEGER;
v, ts, te: INTEGER
END;
PROCEDURE SetDAC (chn, x: INTEGER);
BEGIN
ASSERT(chn DIV 2 = 0);
IF chn = 0 THEN
SYSTEM.PUT(MCU.DACDHR12R1, x)
ELSE
SYSTEM.PUT(MCU.DACDHR12R2, x)
END
END SetDAC;
PROCEDURE Receive3 (id: CHAR; a: ARRAY OF CHAR; len: INTEGER);
VAR ok, echo: BOOLEAN; v, t, r: INTEGER;
BEGIN echo := FALSE;
IF (id = 11X) OR (id = 12X) THEN
IF len = 8 THEN
r := 0;
MF.ReadIntLE(a, r, v);
MF.ReadIntLE(a, r, t);
IF (v >= 0) & (v < 4096) THEN
IF id = 11X THEN
SetDAC(0, v);
channels[0].timeDAC := t
ELSE
SetDAC(1, v);
channels[1].timeDAC := t
END;
echo := TRUE
END
END
ELSIF id = 15X THEN
IF len = 24 THEN
r := 0;
MF.ReadIntLE(a, r, channels[0].v);
MF.ReadIntLE(a, r, channels[0].ts);
MF.ReadIntLE(a, r, channels[0].te);
MF.ReadIntLE(a, r, channels[1].v);
MF.ReadIntLE(a, r, channels[1].ts);
MF.ReadIntLE(a, r, channels[1].te);
both := TRUE;
echo := TRUE
END
END;
IF echo THEN TP3.Send(id, SYSTEM.ADR(a), len, ok) END
END Receive3;
PROCEDURE OnTimer;
VAR over1, over2: BOOLEAN;
chn: INTEGER;
PROCEDURE Test (chn: INTEGER): BOOLEAN;
VAR over: BOOLEAN;
BEGIN
over := FALSE;
IF channels[chn].ts > 0 THEN
DEC(channels[chn].ts)
ELSIF channels[chn].ts = 0 THEN
DEC(channels[chn].ts);
SetDAC(chn, channels[chn].v)
ELSE
IF channels[chn].te > 0 THEN
DEC(channels[chn].te)
ELSIF channels[chn].te = 0 THEN
DEC(channels[chn].te);
SetDAC(chn, 0);
over := TRUE
ELSE
over := TRUE
END
END;
RETURN over
END Test;
BEGIN
IF both THEN
over1 := Test(0);
over2 := Test(1);
both := ~ (over1 & over2)
ELSE
chn := nChannels;
REPEAT DEC(chn);
IF channels[chn].timeDAC > 0 THEN
DEC(channels[chn].timeDAC)
ELSIF channels[chn].timeDAC = 0 THEN
SetDAC(chn, 0);
DEC(channels[chn].timeDAC)
END
UNTIL chn = 0;
INC(cnt0);
IF cnt0 MOD periodicTimerFreq = 0 THEN
SYSTEM.PUT(MCU.GPIODBSRR, {12 + 16}) (* !~PD12 *)
ELSIF cnt0 MOD periodicTimerFreq = periodicTimerFreq DIV 2 THEN
SYSTEM.PUT(MCU.GPIODBSRR, {12}) (* !PD12 *)
END
END
END OnTimer;
PROCEDURE MainLoop;
BEGIN
REPEAT
IF PeriodicTimer.OnTimer() THEN
OnTimer
END;
TP3.Receive(Receive3);
ARMv7M.WFI
UNTIL FALSE
END MainLoop;
PROCEDURE Init;
VAR chn: INTEGER;
PROCEDURE InitLED;
BEGIN
PinCfg.Configure(PinCfg.D, 12, PinCfg.output,
PinCfg.pushPull, PinCfg.low, PinCfg.noPull, 0)
END InitLED;
PROCEDURE InitDAC;
VAR x: SET;
BEGIN
(* enable GPIOA = 0 *)
SYSTEM.GET(MCU.RCCAHB1ENR, x);
SYSTEM.PUT(MCU.RCCAHB1ENR, x + {0});
(* enable DAC clock, DACEN = 29 *)
SYSTEM.GET(MCU.RCCAPB1ENR, x);
SYSTEM.PUT(MCU.RCCAPB1ENR, x + {29});
(* PA4, PA5: AIN *)
SYSTEM.GET(MCU.GPIOAMODER, x);
SYSTEM.PUT(MCU.GPIOAMODER, x - {8..11});
(* Disable buffer BOFF1 = 1, BOFF2 = 16 *)
SYSTEM.GET(MCU.DACCR, x);
x := x - {1, 17};
(* Reset TEN1 = 2 and TEN2 = 18 *)
x := x - {2, 18};
SYSTEM.PUT(MCU.DACCR, x);
(* Enable EN1 = 0, EN2 = 16 *)
SetDAC(0, 0);
SetDAC(1, 0);
SYSTEM.GET(MCU.DACCR, x);
SYSTEM.PUT(MCU.DACCR, + {0, 16})
END InitDAC;
BEGIN
both := FALSE;
cnt0 := 0;
chn := nChannels;
REPEAT DEC(chn);
channels[chn].timeDAC := 0
UNTIL chn = 0;
InitLED;
InitDAC;
TP3.Init(19200, TP3.parityNone);
PeriodicTimer.Init(periodicTimerFreq)
END Init;
BEGIN
Init;
MainLoop
END IvanTestDAC1.
Код:
MODULE IvanSysTick0;
(*
Alexander Shiryaev, 2015.03
SysTick timer for producing periodic events
*)
IMPORT SYSTEM, ARMv7M := MicroARMv7M,
Sys := MicroSTM32F405System;
VAR flag: BOOLEAN;
PROCEDURE* SysTickIntHandler;
BEGIN flag := TRUE
END SysTickIntHandler;
PROCEDURE Init* (freq: INTEGER);
CONST delay1sec = Sys.HCLK DIV 8; (* STM32F40x *)
(* SYSTCSR bits: *)
ENABLE = 0; TICKINT = 1; CLKSOURCE = 2;
VAR x: INTEGER;
BEGIN
SYSTEM.PUT(ARMv7M.SYSTCSR, {}); (* disable SysTick *)
flag := FALSE;
(* NOTE: timer is 24-bit! *)
(* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babieigh.html *)
x := delay1sec DIV freq - 1;
ASSERT(x > 0);
ASSERT(x < 1000000H);
SYSTEM.PUT(ARMv7M.SYSTRVR, x);
SYSTEM.PUT(ARMv7M.SYSTCVR, 0); (* any write to current clears it *)
SYSTEM.PUT(Sys.VectorsOrg + ARMv7M.SysTick * 4, SysTickIntHandler);
SYSTEM.PUT(ARMv7M.SYSTCSR, {ENABLE,TICKINT}) (* enable timer with clock source of system clock / 2 with interrupts *)
END Init;
PROCEDURE OnTimer* (): BOOLEAN;
VAR res: BOOLEAN;
BEGIN
res := flag; IF res THEN flag := FALSE END
RETURN res
END OnTimer;
END IvanSysTick0.