Compare commits

...

6 Commits
main ... master

6 changed files with 341 additions and 45 deletions

116
README.md
View File

@ -1,3 +1,115 @@
# Quartus # Преобразователь 3.3В → 24В для входа TX01
Мигаем светодиодом ## Назначение
Преобразователь уровня сигнала с GPIO микроконтроллера 3.3В (STM32F407) на дискретный вход 24В (TX01) с инверсией логики. Подходит для подключения ПЛИС/МК к промышленным входам 24В. [web:10]
## Схема
```text
+24V (внешний источник)
GPIO pin_10 │
│ ┌┴┐
│ │ │ R3 = 4.7kΩ
│ └┬┘
│ │
│ ├──────────► TX01 (вход 24V)
│ │
└─[ 10kΩ ]─┬[B] │
│ │
┌┴┐ ┌──┴──┐
R2 │ │ │ C │
100kΩ │ │ │ NPN │ Q1: BC547B / 2N2222A / 2N3904
└┬┘ │ Q1 │
│ │ E │
GND └──┬──┘
│ │
─┴─ GND
GND │
GND ─────────────┴──────────── GND (общий)
```
## Принцип работы
R1 (10kΩ) и R2 (100kΩ) образуют резистивный делитель напряжения на базе транзистора. [web:8]
- При GPIO = 3.3В на базе формируется около 3.0В (до открытия перехода база‑эмиттер). [web:8]
- При \(V_{BE} \approx 0.7В\) транзистор открывается и входит в насыщение, коллектор притягивается к GND. [web:8]
- Избыток напряжения рассеивается на делителе R1R2. [web:8]
Выход TX01 подтянут к +24В через R3 (4.7kΩ):
- Когда транзистор закрыт, TX01 ≈ 24В (логическая 1 для входа 24В). [web:8]
- Когда транзистор открыт, TX01 ≈ 0.2В (насыщение, логический 0). [web:8]
## Таблица состояний
| GPIO PA5 | Транзистор | TX01 | Логика TX01 |
|----------|------------|--------|-------------|
| 0В | Закрыт | ~24В | HIGH |
| 3.3В | Открыт | ~0.2В | LOW |
Инверсия логики:
- LOW на GPIO → HIGH на TX01
- HIGH на GPIO → LOW на TX01
## Расчеты
Ток базы при GPIO = 3.3В:
\[
I_b = \frac{V_{in} - V_{BE}}{R1 + R2}
\]
\[
I_b = \frac{3.3V - 0.7V}{110k\Omega} \approx 24\ \mu A
\]
Ток коллектора (при подтяжке 24В через 4.7kΩ):
\[
I_c = \frac{24V}{4.7k\Omega} \approx 5.1\ mA
\]
Требуемый коэффициент усиления:
\[
\beta = \frac{I_c}{I_b} \approx \frac{5.1mA}{24\mu A} \approx 212
\]
Подходящие транзисторы (по \(h_{FE}\) в активном режиме, с запасом для насыщения): [web:8][web:9]
- BC547B: \(hFE \approx 200450\) [web:8]
- 2N2222A: \(hFE \approx 100300\) [web:9]
- 2N3904: \(hFE \approx 100300\) [web:9]
## Назначение элементов
- R1 (10kΩ)
- Ограничивает ток базы.
- Формирует верхнее плечо делителя напряжения.
- R2 (100kΩ)
- Обеспечивает разряд базы при выключении.
- Не дает базе и GPIO «плавать».
- Ускоряет выключение транзистора.
- Формирует нижнее плечо делителя.
- R3 (4.7kΩ)
- Pullup к +24В для входа TX01.
- Ограничивает ток коллектора транзистора.
- Формирует уровень HIGH на входе 24В.
- Q1 (NPN: BC547B / 2N2222A / 2N3904)
- Работает как ключ в насыщении. [web:8][web:9]
- Коммутирует вход TX01 на землю.
- Обеспечивает развязку 3.3В GPIO и 24В линии.
## Особенности применения
- Требуется общий GND между STM32/ПЛИС и источником 24В. [web:10]
- Логика инверсная, это нужно учесть в прошивке. [web:10]
- Ток через вход TX01 ≈ 5 mА при 24В, что подходит для большинства промышленных дискретных входов. [web:8]
- Схема подходит для частот от единиц герц до десятков килогерц (ограничения по R1/R2 и паразитным емкостям). [web:8]

51
UML/activity.plantuml Normal file
View File

@ -0,0 +1,51 @@
@startuml
start
:posedge clk;
'--- Step timer ---
if (step_cnt >= (freq_idx == 1 ? STEP_2SEC_MAX : STEP_4SEC_MAX)) then (yes)
:step_cnt := 0;
if (freq_idx == 5) then (yes)
:freq_idx := 0;
else (no)
:freq_idx := freq_idx + 1;
endif
else (no)
:step_cnt := step_cnt + 1;
endif
'--- Recalculate half-period ---
:max_count := calc_max_count(freq_idx);
'--- Blink generation for led ---
if (max_count == 0) then (0 Hz)
:blink_cnt := 0;
note right
led_base сохраняет предыдущее
значение (нет мигания)
end note
else (f > 0)
if (blink_cnt >= max_count) then (toggle)
:blink_cnt := 0;
:led_base := ~led_base;
else (count)
:blink_cnt := blink_cnt + 1;
endif
endif
'--- 1 Hz generation for pin ---
if (pin_cnt >= PIN_1HZ_HALF_MAX) then (toggle)
:pin_cnt := 0;
:pin_base := ~pin_base;
else (count)
:pin_cnt := pin_cnt + 1;
endif
'--- Outputs (combinational) ---
:led = ~led_base;
:pin = pin_base;
:pin_10 = led;
stop
@enduml

BIN
UML/activity.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

66
UML/state.plantuml Normal file
View File

@ -0,0 +1,66 @@
@startuml
[*] --> F0 : reset/power-up
state "Blink frequency\nstates" as BlinkFreq {
state F0
state F10
state F20
state F30
state F40
state F50
}
' --- Notes ---
note right of F0
freq_idx = 0
f = 0 Hz (LED заморожен)
step_cnt считает до STEP_4SEC_MAX
end note
note right of F10
freq_idx = 1
f = 10 Hz
max_count = F_CLK/(2*10)-1
step_cnt считает до STEP_2SEC_MAX
end note
note right of F20
freq_idx = 2
f = 20 Hz
max_count = F_CLK/(2*20)-1
step_cnt считает до STEP_4SEC_MAX
end note
note right of F30
freq_idx = 3
f = 30 Hz
max_count = F_CLK/(2*30)-1
step_cnt считает до STEP_4SEC_MAX
end note
note right of F40
freq_idx = 4
f = 40 Hz
max_count = F_CLK/(2*40)-1
step_cnt считает до STEP_4SEC_MAX
end note
note right of F50
freq_idx = 5
f = 50 Hz
max_count = F_CLK/(2*50)-1
step_cnt считает до STEP_4SEC_MAX
end note
' --- Transitions ---
F0 --> F10 : step_cnt >= STEP_4SEC_MAX
F10 --> F20 : step_cnt >= STEP_2SEC_MAX
F20 --> F30 : step_cnt >= STEP_4SEC_MAX
F30 --> F40 : step_cnt >= STEP_4SEC_MAX
F40 --> F50 : step_cnt >= STEP_4SEC_MAX
F50 --> F0 : step_cnt >= STEP_4SEC_MAX
F0 --> [*] : external reset
@enduml

BIN
UML/state.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

153
blink.v
View File

@ -1,55 +1,122 @@
module blink #( module blink #(
// Выбор частоты мигания (F_BLINK), Гц: // Input clock frequency in Hz
// 1 -> 1 parameter integer F_CLK = 50_000_000 // 50 MHz
// 2.5 -> 25 (см. ниже, делим на 10)
// 5 -> 5
// 10 -> 10
parameter integer MODE = 4 // по умолчанию 1 Гц
)( )(
input wire clk, // 50 MHz input wire clk,
output reg led, output wire led,
output reg pin, output wire pin,
output reg pin_10 output wire pin_10
); );
localparam integer F_CLK = 50_000_000; //---------------------------------------------------------
// Step duration:
// - for 0.5 Hz : 2 s
// - for others : 4 s
//---------------------------------------------------------
localparam integer STEP_2SEC_MAX = (F_CLK * 2) - 1;
localparam integer STEP_4SEC_MAX = (F_CLK * 4) - 1;
// Предрасчитанные MAX_COUNT для половины периода: // Step timer counter
// reg [31:0] step_cnt = 32'd0;
// 1 Гц: T=1 c T/2=0.5 c 25_000_000
// 2.5 Гц: T=0.4 c T/2=0.2 c 10_000_000
// 5 Гц: T=0.2 c T/2=0.1 c 5_000_000
// 10 Гц: T=0.1 c T/2=0.05 c 2_500_000
localparam integer MAX_1HZ = 25_000_000 - 1; // Frequency index: 0..5 0, 10, 20, 30, 40, 50 Hz
localparam integer MAX_2_5HZ = 10_000_000 - 1; reg [2:0] freq_idx = 3'd0;
localparam integer MAX_5HZ = 5_000_000 - 1;
localparam integer MAX_10HZ = 2_500_000 - 1;
// Выбор MAX_COUNT по MODE // Half-period counter and current half-period length in clock cycles
// MODE: reg [31:0] blink_cnt = 32'd0;
// 1 -> 1 Гц reg [31:0] max_count = 32'd0;
// 2 -> 2.5 Гц
// 3 -> 5 Гц
// 4 -> 10 Гц
localparam integer MAX_COUNT =
(MODE == 1) ? MAX_1HZ :
(MODE == 2) ? MAX_2_5HZ :
(MODE == 3) ? MAX_5HZ :
(MODE == 4) ? MAX_10HZ :
MAX_1HZ; // по умолчанию 1 Гц
reg [25:0] cnt; // хватает до > 33 млн (2^25 = 33_554_432) // Base LED signal (before output inversion)
reg led_base = 1'b0;
always @(posedge clk) begin //---------------------------------------------------------
if (cnt >= MAX_COUNT) begin // 1 Hz generator for pin: divider from F_CLK
cnt <= 0; // Period 1 Hz = 1 s, half-period = 0.5 s
led <= ~led; //---------------------------------------------------------
pin <= led; localparam integer PIN_1HZ_HALF_MAX = (F_CLK / 2) - 1;
pin_10 <= led;
end else begin reg [31:0] pin_cnt = 32'd0;
cnt <= cnt + 1; reg pin_base = 1'b0;
//---------------------------------------------------------
// Function to calculate half-period in clock cycles
//---------------------------------------------------------
function [31:0] calc_max_count;
input [2:0] idx;
integer f;
begin
// Frequency in Hz: 0, 10, 20, 30, 40, 50
f = idx * 10;
if (f == 0) begin
// Special case: 0 Hz no blinking
calc_max_count = 32'd0;
end else begin
// Half-period: F_CLK / (2 * f)
calc_max_count = (F_CLK / (2 * f)) - 1;
end
end end
end endfunction
//---------------------------------------------------------
// Main process: step timing, frequency selection,
// blink generation
//---------------------------------------------------------
always @(posedge clk) begin
//-----------------------------------------------------
// Step timer: change frequency every 2 or 4 seconds
//-----------------------------------------------------
if (step_cnt >= (freq_idx == 3'd1 ? STEP_2SEC_MAX : STEP_4SEC_MAX)) begin
step_cnt <= 32'd0;
// Cycle through 0123450...
if (freq_idx == 3'd5)
freq_idx <= 3'd0;
else
freq_idx <= freq_idx + 3'd1;
end else begin
step_cnt <= step_cnt + 32'd1;
end
//-----------------------------------------------------
// Recalculate half-period for current frequency
//-----------------------------------------------------
max_count <= calc_max_count(freq_idx);
//-----------------------------------------------------
// Blink generation for led
//-----------------------------------------------------
if (max_count == 32'd0) begin
// 0 Hz: hold current state, no blinking
blink_cnt <= 32'd0;
// led_base keeps its last value
end else begin
if (blink_cnt >= max_count) begin
blink_cnt <= 32'd0;
led_base <= ~led_base;
end else begin
blink_cnt <= blink_cnt + 32'd1;
end
end
//-----------------------------------------------------
// 1 Hz generation for pin (independent of freq_idx)
//-----------------------------------------------------
if (pin_cnt >= PIN_1HZ_HALF_MAX) begin
pin_cnt <= 32'd0;
pin_base <= ~pin_base;
end else begin
pin_cnt <= pin_cnt + 32'd1;
end
end
//---------------------------------------------------------
// Outputs:
// led = inverted base signal (variable frequency)
// pin = 1 Hz
// pin_10 = inverted pin
//---------------------------------------------------------
assign led = ~led_base;
assign pin = pin_base;
assign pin_10 = led;
endmodule endmodule