Tải trọng điện tử thông minh dựa trên CH32V307VCT6 mã nguồn mở, tác phẩm cuộc thi nhúng mã nguồn mở, bao gồm sơ đồ nguyên lý, PCB, mã nguồn chương trình, báo cáo tác phẩm.
Cuộc thi Thiết kế Chip và Hệ thống Nhúng năm 2023, hạng hai quốc gia.
Được sửa đổi trong nửa tháng dựa trên tải trọng điện tử phiên bản Holtek được thực hiện trước đó, chuyển chương trình sang vi điều khiển CH32, sử dụng hệ thống RT-Thread, tối ưu hóa mã, hoàn thành trong thời gian gấp rút, được thực hiện rất tầm thường, xin đừng chỉ trích.
Video trình diễn tác phẩm: https://www.bilibili.com/video/BV1Zu4y1m7Zd/
Tải trọng điện tử thông minh mã nguồn mở dựa trên HT32F52352, tác phẩm Holtek Cup mã nguồn mở: https://blog.zeruns.com/archives/784.html
Tác phẩm mã nguồn mở này chỉ dành cho tham khảo và học tập, không khuyến khích sao chép, có nhiều tác phẩm tải trọng điện tử mã nguồn mở tốt hơn và hoàn thiện hơn trên nền tảng mã nguồn mở Lichee!
Liên kết mã nguồn mở của dự án trên nền tảng mã nguồn mở Lichee: https://url.zeruns.com/Et4x4
Nhóm trao đổi kỹ thuật điện tử/vi điều khiển: 2169025065
Trang web chính thức Qinheng có thể yêu cầu miễn phí mẫu bảng phát triển: https://url.zeruns.com/h9a99
Tải trọng điện tử là gì
Tải trọng điện tử là một thiết bị điện tử được sử dụng để mô phỏng môi trường tải trọng thực tế nhằm kiểm tra hiệu suất của nguồn điện hoặc mạch điện tử. So với việc sử dụng điện trở có thể điều chỉnh công suất lớn hoặc sợi điện trở truyền thống, tải trọng điện tử có nhiều ưu điểm như tham số có thể điều chỉnh, dễ sử dụng, v.v. Cho dù là phát triển dự án điện tử chuyên nghiệp hay những người yêu thích điện tử nghiệp dư, máy tải trọng điện tử là một trong những thiết bị không thể thiếu.
Tải trọng điện tử có thể được chia thành tải trọng điện tử xoay chiều và tải trọng điện tử một chiều dựa trên loại nguồn điện được kiểm tra. Từ chức năng, các loại phổ biến bao gồm bốn loại: dòng điện không đổi, điện áp không đổi, điện trở không đổi và công suất không đổi. Vì hầu hết các nguồn điện phổ biến mà chúng ta thấy đều là nguồn điện một chiều có điện áp không đổi. Khi kiểm tra loại nguồn điện này, điều chính được kiểm tra là khả năng xuất dòng điện của nó. Do đó, trong hầu hết các tình huống ứng dụng, tải trọng điện tử dòng điện không đổi là loại phổ biến nhất. Tải trọng điện tử có thể được chia thành hai loại: điều khiển số và tương tự dựa trên phương pháp điều khiển. So với tải trọng điện tử được điều khiển bằng mạch tương tự thuần túy, tải trọng điện tử được điều khiển số sử dụng điều khiển kỹ thuật số, trực quan hơn trong điều chỉnh tham số, có nhiều chức năng, mở rộng đơn giản, và có thể dễ dàng thực hiện tự động hóa kiểm tra.
Giới thiệu dự án
Tác phẩm này sử dụng vi điều khiển Qinheng CH32V307VCT6 làm chip điều khiển chính để thiết kế tải trọng điện tử, được cấp nguồn bằng pin lithium 18650, dễ dàng mang theo.
Phương pháp điều khiển là thông qua vi điều khiển xuất ra một điện áp một chiều thông qua DAC làm điện áp tham chiếu được so sánh với điện áp được khuếch đại bằng bộ khuếch đại hoạt động và lấy mẫu dòng điện/điện áp, đầu ra của bộ khuếch đại hoạt động điều khiển ống MOS, từ đó thực hiện điện áp không đổi/dòng điện không đổi.
Màn hình cảm ứng sử dụng màn hình cổng nối tiếp 2,8 inch của Taojingchi, mô hình: TJC3224T028_011R.
Tản nhiệt sử dụng tản nhiệt máy chủ 2U với chân 1356/1366, thổi bên.
Chương trình dự án được phát triển bằng RT-Thread Studio. Thiết kế mạch sử dụng phần mềm EDA Lichee.
Điện áp và dòng điện đầu vào tối đa là 100V/10A, công suất tối đa 200W.
Hình ảnh thực tế
Lúc đó không chụp nhiều ảnh, chỉ tìm được vài cái, bạn có thể xem video trình diễn.
Địa chỉ tải tài liệu
Các tài liệu trong liên kết dưới đây bao gồm: sơ đồ nguyên lý mạch, tệp dự án EDA Lichee, tệp PCB để sản xuất bảng, mã nguồn chương trình, tệp dự án màn hình cổng nối tiếp, hướng dẫn chip.
Địa chỉ tải xuống không giới hạn tốc độ 123 Cloud Disk: https://www.123pan.com/ps/2Y9Djv-6NevH.html
Địa chỉ tải xuống Baidu Netdisk: https://pan.baidu.com/s/17YSlBZ6F1M18k7JGa7FlVA?pwd=buxx Mã trích xuất: buxx
Địa chỉ mua linh kiện
- Chip CH32V307VCT6: https://s.click.taobao.com/T8MSZot
- Bảng phát triển CH32V307VCT6: https://s.click.taobao.com/2JBSZot
- Chip INA199A1: https://s.click.taobao.com/XLuweot
- Mẫu điện trở dán 0805: https://s.click.taobao.com/p8YSGpt
- Mẫu tụ dán 0805: https://u.jd.com/9uvZoBd
- Chip XL1509: https://s.click.taobao.com/DOcRZot
- Màn hình cổng nối tiếp: https://s.click.taobao.com/pyzleot
Khuyến nghị mua linh kiện tại Lichee Mall: https://activity.szlcsc.com/invite/D03E5B9CEAAE70A4.html
Sơ đồ nguyên lý
Bảng công suất
Bảng nguồn điện
Bảng điều khiển
PCB
Bảng công suất
Lớp trên
Lớp dưới
Bảng nguồn điện
Lớp trên
Lớp dưới
Bảng điều khiển
Lớp trên
Lớp dưới
Các dự án mã nguồn mở khác được khuyến nghị- Đã tạo bộ thu thập dữ liệu điện ba pha mã nguồn mở, có thể dễ dàng giám sát tình hình sử dụng điện ở nhà: https://blog.zeruns.com/archives/771.html
- Mẫu dự án thư viện chuẩn STM32F407 với U8g2 đã được chuyển cổng: https://blog.zeruns.com/archives/722.html
- Bảng hệ thống tối thiểu Qinheng CH32V307VCT6 mã nguồn mở: https://blog.zeruns.com/archives/726.html
- Mô-đun nguồn DCDC có thể điều chỉnh tự động nâng hạ LM25118: https://blog.zeruns.com/archives/727.html
- Mô-đun nâng áp đồng bộ chỉnh lưu công suất cao EG1164 mã nguồn mở, hiệu suất tối đa 97%: https://blog.zeruns.com/archives/730.html
- Nút giám sát môi trường 4G dựa trên Hezhou Air700E (dữ liệu nhiệt độ, độ ẩm, áp suất, v.v.), tải lên nền tảng IoT Alibaba Cloud thông qua MQTT: https://blog.zeruns.com/archives/747.html
Mã chính
Tệp main.c
/********************************** (C) COPYRIGHT *******************************
* File Name : main.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Main program body.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
* https://blog.zeruns.com
*******************************************************************************/
#include "ch32v30x.h"
#include
``````c
#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#include <rthw.h>
#include "drivers/pin.h"
#include <board.h>
#include <rtdbg.h>
#include <u8g2_port.h>
#include <qpid.h>
#include "USART.h"
#include "KEY.h"
#include "DAC.h"
#include "PWM.h"
/* Định nghĩa kiểu toàn cục */
/* Định nghĩa toàn cục */
#define WDT_DEVICE_NAME "wdt" /* Tên thiết bị watchdog */
static rt_device_t wdg_dev; /* Xử lý thiết bị watchdog */
/* Điện áp tham chiếu ADC */
#define VREF 3.3
/* Điện áp nguồn */
#define VCC 3.3
/* Dữ liệu bù hiệu chỉnh */
#define V0_COMP 1.000 // Phạm vi điện áp 0.0325 lần
#define V1_COMP 1.000 // Phạm vi điện áp 0.0947 lần
#define V2_COMP 1.000 // Phạm vi điện áp 0.6175 lần
#define YIF1_COMP 1.00 // Bù lấy mẫu dòng điện MOS 1
#define YIF2_COMP 1.00 // Bù lấy mẫu dòng điện MOS 2
#define DAC1_COMP 1.00 // Hệ số bù đầu ra DAC1(VREF)
#define IREF2_COMP 1.00 // Hệ số bù đầu ra IREF2
#define DAC2_COMP 1.00 // Bù đầu ra DAC2(IREF1)
/* Số lần tính giá trị trung bình lấy mẫu ADC */
#define ADC_count 3
/* Hệ số lọc bộ lọc thông thấp bậc nhất */
#define dPower1 0.5
/* Số hiệu chân, được xác định bằng cách xem tệp trình điều khiển drv_gpio.c */
#define OLED_I2C_PIN_SCL 22 //PB6
#define OLED_I2C_PIN_SDA 23 //PB7
#define LED2 59 //PD11
#define LED1 60 //PD12
#define MCU_G0 62 //PD14
#define MCU_G1 63 //PD14
/* Biến toàn cục */
u8g2_t u8g2; // Biến cấu trúc u8g2
rt_uint16_t AD_Value[4]; // Dữ liệu lấy mẫu ADC
// Định nghĩa biến liệt kê trang chế độ
enum mode_type
{
menu = 0, // Menu
CC, // Dòng điện không đổi
CV, // Điện áp không đổi
CR, // Điện trở không đổi
CW // Công suất không đổi
};
volatile uint8_t Eload_Out = 0; // Trạng thái bật/tắt đầu ra tải điện tử
volatile uint8_t mode = menu; // Chế độ hiện tại
volatile uint8_t voltage_dw = 0; // Phạm vi lấy mẫu điện áp, 0 là 0.0325 lần, 2 là 0.6175 lần, 1 là 0.0947 lần
volatile double YVF, YIF1, YIF2, YIF, VBAT; // Điện áp và dòng điện hiện tại
volatile double ISET, VSET, RSET, PSET; // Giá trị đặt dòng điện, điện áp, điện trở, công suất
volatile uint32_t YVF_SUM, YIF1_SUM, YIF2_SUM, VBAT_SUM; // Tổng tính toán để tính giá trị trung bình điện áp và dòng điện
volatile uint8_t AVG_count = 0; // Giá trị đếm tích lũy tính giá trị trung bình dòng điện
volatile uint8_t YVF_AVG_count = 0; // Giá trị đếm tích lũy tính giá trị trung bình điện áp
volatile uint8_t VBAT_count = 0; // Giá trị đếm tích lũy tính giá trị trung bình điện áp pin
volatile uint8_t Key_ONOFF = 0; // Trạng thái nút bật/tắt tải điện tử có được nhấn hay không
static qpid_t qpid_CC; // Con trỏ dữ liệu điều khiển PID
static qpid_t qpid_CV; // Con trỏ dữ liệu điều khiển PID
static qpid_t qpid_CR; // Con trỏ dữ liệu điều khiển PID
static qpid_t qpid_CW; // Con trỏ dữ liệu điều khiển PID
static double I_SET, V_SET, R_SET, P_SET;
/* Khai báo hàm */
void OLED_Init(void);
static int IWDG_Init();
static void thread1_sysLED_entry(void *parameter);
static void thread2_OLED_entry(void *parameter);
static void thread3_ADC_entry(void *parameter);
static void thread4_HMI_GetDate_entry(void *parameter);
static void thread5_ONOFF_entry(void *parameter);
static void thread7_HMI_Display_entry(void *parameter);
static void thread8_FAN_entry(void *parameter);
static void thread9_CWCR_entry(void *parameter);
static void thread10_BlueTooth_entry(void *parameter);
void CW_mode(void);
void CR_mode(void);
void key123(void);
void Thread_Init(void);
void SYS_Init(void);
void PID(void);
/*********************************************************************
* @fn main
*
* @brief Chương trình chính.
*
* @return không
*/
int main(void)
{
rt_kprintf("MCU: CH32V307\n");
rt_kprintf("SysClk: %dHz\n", SystemCoreClock);
SYS_Init();
while (1)
{
// Bảo vệ quá dòng và quá công suất
if (YIF > 10 | YVF * YIF > 300)
{
if (Eload_Out == 1)
{
Key_ONOFF = 1;
}
}
rt_thread_mdelay(20);
}
}
/* Khởi tạo hệ thống */
void SYS_Init(void)
{
IWDG_Init(); // Khởi tạo watchdog
UART_Init(); // Khởi tạo UART 3
HMILCD_Send("page 0"); // Chuyển đến trang khởi động
Dac_Init(); // Khởi tạo DAC
PWM_Init(); // Khởi tạo PWM
rt_pin_mode(MCU_G0, PIN_MODE_OUTPUT); // Đặt chế độ cổng IO là đầu ra
rt_pin_mode(MCU_G1, PIN_MODE_OUTPUT);
rt_pin_write(MCU_G0, PIN_LOW); // Xuất mức thấp
rt_pin_write(MCU_G1, PIN_LOW);
Thread_Init(); // Tạo luồng
}
/* Khởi tạo luồng */
void Thread_Init(void)
{
rt_thread_t tid = NULL; // Định nghĩa con trỏ khối điều khiển luồng
/* Tạo luồng */
tid = rt_thread_create("SYS_LED", thread1_sysLED_entry, NULL, 512, 30, 5);
// Tạo một luồng có tên SYS_LED, hàm nhập là thread1_sysLED_entry, tham số là NULL, kích thước ngăn xếp là 256 byte, ưu tiên là 30, lát thời gian là 5 tick
if (tid != RT_NULL) // Kiểm tra xem luồng có được tạo thành công không
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread sysLED create success");
}
else
{
LOG_E("thread1 sysLED create failed...");
}
/*
tid = rt_thread_create("OLED_Display", thread2_OLED_entry, NULL, 2048, 25, 30);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread2 OLED create success");
}
else
{
LOG_E("thread2_OLED create failed...");
}*/
tid = rt_thread_create("ADC", thread3_ADC_entry, NULL, 1536, 18, 30);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread3 ADC create success");
}
else
{
LOG_E("thread3 ADC create failed...");
}
tid = rt_thread_create("HMI_GetDate", thread4_HMI_GetDate_entry, NULL, 2048, 23, 30);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread4 HMI_GetDate create success");
}
else
{
LOG_E("thread4 HMI_GetDate create failed...");
}
tid = rt_thread_create("ONOFF", thread5_ONOFF_entry, NULL, 1024, 15, 25);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread5 ONOFF create success");
}
else
{
LOG_E("thread5 ONOFF create failed...");
}
tid = rt_thread_create("KEY", thread6_KEY_entry, NULL, 512, 20, 20);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread6 KEY create success");
}
else
{
LOG_E("thread6 KEY create failed...");
}
tid = rt_thread_create("HMI_Display", thread7_HMI_Display_entry, NULL, 1024, 25, 30);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread7 HMI_Display create success");
}
else
{
LOG_E("thread7 HMI_Display create failed...");
}
tid = rt_thread_create("FAN", thread8_FAN_entry, NULL, 512, 26, 15);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread8 FAN create success");
}
else
{
LOG_E("thread8 FAN create failed...");
}
tid = rt_thread_create("CWCR", thread9_CWCR_entry, NULL, 512, 19, 15);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread9 CWCR create success");
}
else
{
LOG_E("thread9 CWCR create failed...");
}
tid = rt_thread_create("BlueTooth", thread10_BlueTooth_entry, NULL, 2048, 23, 30);
if (tid != RT_NULL)
{
if (rt_thread_startup(tid) == RT_EOK) // Khởi động luồng
LOG_D("thread10 BlueTooth create success");
}
else
{
LOG_E("thread10 BlueTooth create failed...");
}
}
``````c
/* Bộ lọc thông thấp bậc một
* Giá trị trả về: iData giá trị lấy mẫu sau khi lọc bậc một */
double lowV1(double com1)
{
static double iLastData1; // Giá trị lần trước
double iData1; // Giá trị tính toán lần này
iData1 = (com1 * dPower1) + (1 - dPower1) * iLastData1; // Tính toán
iLastData1 = iData1; // Lưu trữ dữ liệu lần này
return iData1; // Trả về dữ liệu
}
double lowV2(double com1)
{
static double iLastData2; // Giá trị lần trước
double iData1; // Giá trị tính toán lần này
iData1 = (com1 * dPower1) + (1 - dPower1) * iLastData2; // Tính toán
iLastData2 = iData1; // Lưu trữ dữ liệu lần này
return iData1; // Trả về dữ liệu
}
u16 lowV3(u16 com1)
{
static u16 iLastData3; // Giá trị lần trước
u16 iData1; // Giá trị tính toán lần này
iData1 = (com1 * dPower1) + (1 - dPower1) * iLastData3; // Tính toán
iLastData3 = iData1; // Lưu trữ dữ liệu lần này
return iData1; // Trả về dữ liệu
}
u16 lowV4(u16 com1)
{
static u16 iLastData3; // Giá trị lần trước
u16 iData1; // Giá trị tính toán lần này
iData1 = (com1 * 0.1) + (1 - 0.1) * iLastData3; // Tính toán
iLastData3 = iData1; // Lưu trữ dữ liệu lần này
return iData1; // Trả về dữ liệu
}
static void idle_hook(void)
{
/* Cho chó ăn trong hàm gọi lại của luồng nhàn rỗi */
rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_KEEPALIVE, NULL);
// rt_kprintf("cho chó ăn!\n ");
}
static int IWDG_Init()
{
rt_err_t ret = RT_EOK;
rt_uint32_t timeout = 1; /* Thời gian tràn, đơn vị: giây */
/* Tìm thiết bị watchdog theo tên thiết bị, lấy handle thiết bị */
wdg_dev = rt_device_find(WDT_DEVICE_NAME);
if (!wdg_dev)
{
rt_kprintf("tìm %s thất bại!\n", WDT_DEVICE_NAME);
return RT_ERROR;
}
/* Khởi tạo thiết bị */
rt_device_init(wdg_dev);
/* Đặt thời gian tràn watchdog */
ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_SET_TIMEOUT, &timeout);
if (ret != RT_EOK)
{
rt_kprintf("đặt %s timeout thất bại!\n", WDT_DEVICE_NAME);
return RT_ERROR;
}
/* Khởi động watchdog */
ret = rt_device_control(wdg_dev, RT_DEVICE_CTRL_WDT_START, RT_NULL);
if (ret != RT_EOK)
{
rt_kprintf("khởi động %s thất bại!\n", WDT_DEVICE_NAME);
return -RT_ERROR;
}
/* Đặt hàm gọi lại của luồng nhàn rỗi */
rt_thread_idle_sethook(idle_hook);
return ret;
}
/* Hàm điểm vào của luồng 1, đèn LED trạng thái hệ thống nhấp nháy */
static void thread1_sysLED_entry(void *parameter)
{
/* Chân LED1 ở chế độ đầu ra */
rt_pin_mode(LED1, PIN_MODE_OUTPUT);
/* Mặc định mức thấp */
rt_pin_write(LED1, PIN_LOW);
while (1)
{
/* Luồng 1 chạy ở mức ưu tiên thấp, liên tục nhấp nháy LED1 */
rt_pin_write(LED1, !rt_pin_read(LED1));
rt_thread_mdelay(500);
}
}
/* Hàm điểm vào của luồng 2, màn hình OLED hiển thị thông tin */
static void thread2_OLED_entry(void *parameter)
{
// Khởi tạo
u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_rtthread_hw_i2c, u8x8_gpio_and_delay_rtthread);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
while (1)
{
char String[26];
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_wqy15_t_chinese3); // Đặt bộ ký tự tiếng Trung
float V0 = AD_Value[0] * VREF / 4096.0;
sprintf(String, "AD0:%d V:%d.%d%d%d", AD_Value[0], (uint8_t) V0, (uint16_t)(V0 * 10.0) % 10,
(uint16_t)(V0 * 100.0) % 100 % 10, (uint16_t)(V0 * 1000.0) % 1000 % 100 % 10); // Định dạng chuỗi ký tự đầu ra vào biến chuỗi
u8g2_DrawStr(&u8g2, 0, 15, String);
float V1 = AD_Value[1] * VREF / 4096.0;
sprintf(String, "AD1:%d V:%d.%d%d%d", AD_Value[1], (uint8_t) V1, (uint16_t)(V1 * 10.0) % 10,
(uint16_t)(V1 * 100.0) % 100 % 10, (uint16_t)(V1 * 1000.0) % 1000 % 100 % 10); // Định dạng chuỗi ký tự đầu ra vào biến chuỗi
u8g2_DrawStr(&u8g2, 0, 31, String);
float V2 = AD_Value[2] * VREF / 4096.0;
sprintf(String, "AD2:%d V:%d.%d%d%d", AD_Value[2], (uint8_t) V2, (uint16_t)(V2 * 10.0) % 10,
(uint16_t)(V2 * 100.0) % 100 % 10, (uint16_t)(V2 * 1000.0) % 1000 % 100 % 10); // Định dạng chuỗi ký tự đầu ra vào biến chuỗi
u8g2_DrawStr(&u8g2, 0, 47, String);
float V3 = AD_Value[3] * VREF / 4096.0;
sprintf(String, "AD3:%d V:%d.%d%d%d", AD_Value[3], (uint8_t) V3, (uint16_t)(V3 * 10.0) % 10,
(uint16_t)(V3 * 100.0) % 100 % 10, (uint16_t)(V3 * 1000.0) % 1000 % 100 % 10); // Định dạng chuỗi ký tự đầu ra vào biến chuỗi
u8g2_DrawStr(&u8g2, 0, 63, String);
u8g2_SendBuffer(&u8g2); // Gửi dữ liệu vùng đệm
rt_thread_mdelay(100); // Trễ 100 mili giây
}
}
/* Hàm điểm vào của luồng 3, xử lý dữ liệu ADC */
static void thread3_ADC_entry(void *parameter)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); // Bật xung nhịp GPIOA và ADC
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Bật xung nhịp DMA1
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // Cấu hình phân chia xung nhịp ADC, chia 6 (72Mhz/6=12Mhz), tần số xung nhịp ADC không được vượt quá 14Mhz
GPIO_InitTypeDef GPIO_InitStructure = { 0 }; // Định nghĩa cấu trúc để cấu hình GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; // Đặt chân GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // Chế độ GPIO là đầu vào tương tự
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // Cấu hình nhóm quy tắc ADC, viết kênh 0 vào chuỗi 1 của nhóm quy tắc, thời gian lấy mẫu 55.5 chu kỳ
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5); // Cấu hình nhóm quy tắc ADC, viết kênh 1 vào chuỗi 2 của nhóm quy tắc, thời gian lấy mẫu 55.5 chu kỳ
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5); // Cấu hình nhóm quy tắc ADC, viết kênh 2 vào chuỗi 3 của nhóm quy tắc, thời gian lấy mẫu 55.5 chu kỳ
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5); // Cấu hình nhóm quy tắc ADC, viết kênh 3 vào chuỗi 4 của nhóm quy tắc, thời gian lấy mẫu 55.5 chu kỳ
ADC_InitTypeDef ADC_InitStructure = { 0 };
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // Cấu hình ADC ở chế độ độc lập
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // Bật chế độ quét trong chế độ đa kênh
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // Đặt bật chế độ chuyển đổi liên tục
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // Đặt chuyển đổi không được khởi động bởi kích hoạt bên ngoài, khởi động bằng phần mềm
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // Đặt dữ liệu ADC căn phải
ADC_InitStructure.ADC_NbrOfChannel = 4; // Số lượng kênh ADC của chuyển đổi quy tắc
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); // Bật ADC1
ADC_ResetCalibration(ADC1); // Đặt lại thanh ghi hiệu chuẩn ADC1.
while (ADC_GetResetCalibrationStatus(ADC1))
; // Chờ kết thúc đặt lại hiệu chuẩn
ADC_StartCalibration(ADC1); // Bắt đầu hiệu chuẩn AD
while (ADC_GetCalibrationStatus(ADC1))
; // Chờ kết thúc hiệu chuẩn
DMA_DeInit(DMA1_Channel1); // Đặt lại bộ điều khiển DMA
DMA_InitTypeDef DMA_InitStructure; // Định nghĩa cấu trúc để cấu hình DMA
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) &ADC1->RDATAR; // Cấu hình địa chỉ ngoại vi là địa chỉ thanh ghi dữ liệu ADC
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) AD_Value; // Cấu hình địa chỉ bộ nhớ là địa chỉ đọc giá trị ADC
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Cấu hình nguồn dữ liệu là ngoại vi, tức là chế độ truyền DMA từ ngoại vi đến bộ nhớ
DMA_InitStructure.DMA_BufferSize = 4; // Đặt kích thước vùng đệm dữ liệu DMA
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Đặt chế độ tăng ngoại vi DMA tắt
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Đặt chế độ tăng bộ nhớ DMA bật
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // Đặt kích thước dữ liệu ngoại vi là nửa từ, tức là hai byte
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // Đặt kích thước dữ liệu bộ nhớ là nửa từ, tức là hai byte
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Đặt chế độ DMA là chế độ truyền vòng
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // Đặt mức ưu tiên kênh truyền DMA cao, khi sử dụng một kênh DMA, cài đặt mức ưu tiên không ảnh hưởng
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // Vì chế độ truyền DMA này là từ ngoại vi đến bộ nhớ, do đó vô hiệu hóa chế độ truyền từ bộ nhớ đến bộ nhớ
DMA_Init(DMA1_Channel1, &DMA_InitStructure); // Khởi tạo kênh 1 của DMA1, kích hoạt phần cứng ADC1 được kết nối trên kênh 1 của DMA1, vì vậy phải sử dụng kênh 1 DMA1
DMA_Cmd(DMA1_Channel1, ENABLE); // Khởi động kênh 1 DMA1
ADC_DMACmd(ADC1, ENABLE); // Bật yêu cầu DMA ADC
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // Vì không sử dụng kích hoạt bên ngoài, nên sử dụng kích hoạt phần mềm chuyển đổi ADC
qpid_init(&qpid_CC); // Khởi tạo dữ liệu điều khiển PID
qpid_set_lmt(&qpid_CC, 0, 10); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CC, 1, 0.001, 0.1); // Đặt hệ số tỷ lệ điều khiển
qpid_init(&qpid_CV); // Khởi tạo dữ liệu điều khiển PID
qpid_set_lmt(&qpid_CV, 31.0, 100); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CV, 0.35, 0.005, 0.001); // Đặt hệ số tỷ lệ điều khiển
```qpid_init(&qpid_CW); // Khởi tạo dữ liệu điều khiển PID
qpid_set_lmt(&qpid_CW, 0.1, 200); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CW, 0.5, 0.003, 0.001); // Đặt hệ số tỷ lệ điều khiển
qpid_init(&qpid_CR); // Khởi tạo dữ liệu điều khiển PID
qpid_set_lmt(&qpid_CR, 0.1, 1000); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CR, 0.35, 0.003, 0.001); // Đặt hệ số tỷ lệ điều khiển
while (1)
{
/*rt_kprintf("AD0:%d V:%f\n", AD_Value[0], AD_Value[0] / 4095.0 * VREF);
rt_kprintf("AD1:%d V:%4.3f\n", AD_Value[1], (float) AD_Value[1] / 4095.0 * VREF);
rt_kprintf("AD2:%d V:%4.3f\n", AD_Value[2], AD_Value[2] / 4095.0 * VREF);*/
if (voltage_dw == 0) // Khi mức lấy mẫu điện áp là 0.0325 lần
{
if (YVF_AVG_count < ADC_count) // Khi nhỏ hơn 15, cộng dồn giá trị lấy mẫu
{
YVF_SUM += AD_Value[0];
YVF_AVG_count++;
}
if (YVF_AVG_count == ADC_count)
{
YVF = YVF_SUM / YVF_AVG_count * VREF / 4096.0 / 0.0325 * V0_COMP; // Tính giá trị điện áp
YVF_AVG_count = 0;
YVF_SUM = 0;
}
if (YVF <= 31.0) // Khi điện áp nhỏ hơn 31V, chuyển đổi mức
{
rt_pin_write(MCU_G0, PIN_LOW);
rt_pin_write(MCU_G1, PIN_HIGH); // Mức lấy mẫu điện áp 0.0947 lần
if (Eload_Out == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5)); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
voltage_dw = 1;
YVF_AVG_count = 0;
YVF_SUM = 0;
qpid_set_lmt(&qpid_CV, 4.6, 33.5); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CV, 0.38, 0.0035, 0.0005); // Đặt hệ số tỷ lệ điều khiển
}
}
else if (voltage_dw == 1) // Khi mức điện áp là 0.0947 lần
{
if (YVF_AVG_count < ADC_count)
{
YVF_SUM += AD_Value[0];
YVF_AVG_count++;
}
if (YVF_AVG_count == ADC_count)
{
YVF = YVF_SUM / YVF_AVG_count * VREF / 4096.0 / 0.0947 * V1_COMP;
YVF_AVG_count = 0;
YVF_SUM = 0;
}
if (YVF >= 33.5) // Khi điện áp lớn hơn 33.5V chuyển sang mức 0.0325 lần
{
rt_pin_write(MCU_G0, PIN_LOW);
rt_pin_write(MCU_G1, PIN_LOW);
if (Eload_Out == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.0325 * 4096 / VREF * DAC1_COMP + 0.5)); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
voltage_dw = 0;
YVF_AVG_count = 0;
YVF_SUM = 0;
qpid_set_lmt(&qpid_CV, 31.0, 100); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CV, 0.5, 0.005, 0.0005); // Đặt hệ số tỷ lệ điều khiển
}
else if (YVF <= 4.6) // Khi điện áp nhỏ hơn 4.6V chuyển đổi mức
{
rt_pin_write(MCU_G0, PIN_HIGH);
rt_pin_write(MCU_G1, PIN_LOW);
if (Eload_Out == 1)
{
uint16_t vset_pwm = (uint16_t)(VSET * 0.6175 * 4096 / VREF * DAC1_COMP + 0.5);
if (vset_pwm > 4065)
vset_pwm = 4095;
DAC_SetChannel1Data(DAC_Align_12b_R, vset_pwm); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
voltage_dw = 2;
YVF_AVG_count = 0;
YVF_SUM = 0;
qpid_set_lmt(&qpid_CV, 0.01, 5.1); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CV, 0.26, 0.0025, 0.0005); // Đặt hệ số tỷ lệ điều khiển
}
}
else if (voltage_dw == 2) // Khi mức điện áp là 0.6175 lần
{
if (YVF_AVG_count < ADC_count)
{
YVF_SUM += AD_Value[0];
YVF_AVG_count++;
}
if (YVF_AVG_count == ADC_count)
{
YVF = YVF_SUM / YVF_AVG_count * VREF / 4096.0 / 0.6175 * V2_COMP;
if (YVF < 0.15)
YVF = 0;
YVF_AVG_count = 0;
YVF_SUM = 0;
}
if (YVF >= 5.1) // Khi điện áp lớn hơn 5.1V, chuyển đổi mức
{
rt_pin_write(MCU_G0, PIN_LOW);
rt_pin_write(MCU_G1, PIN_HIGH);
if (Eload_Out == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5)); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
voltage_dw = 1;
YVF_AVG_count = 0;
YVF_SUM = 0;
qpid_set_lmt(&qpid_CV, 4.6, 33.5); // Đặt giới hạn PID
qpid_set_ratio(&qpid_CV, 0.38, 0.0035, 0.0005); // Đặt hệ số tỷ lệ điều khiển
}
}
if (AVG_count < ADC_count)
{
YIF1_SUM += AD_Value[1]; // Cộng dồn dòng điện của MOS 1
YIF2_SUM += AD_Value[2]; // Cộng dồn dòng điện của MOS 2
AVG_count++;
}
if (AVG_count == ADC_count)
{
YIF1 = YIF1_SUM / AVG_count * VREF / 4096.0 / 50 / 0.01 * YIF1_COMP - 0.007;
YIF2 = YIF2_SUM / AVG_count * VREF / 4096.0 / 50 / 0.01 * YIF2_COMP - 0.007;
YIF = YIF1 + YIF2;
if (YIF < 0.008)
YIF = 0;
AVG_count = 0;
YIF1_SUM = 0;
YIF2_SUM = 0;
PID();
}
if (VBAT_count < 5)
{
VBAT_SUM += lowV4(AD_Value[3]); // Cộng dồn giá trị lấy mẫu điện áp pin
VBAT_count++;
}
if (VBAT_count == 5)
{
VBAT = VBAT_SUM / VBAT_count * VREF / 4096.0 / 0.3535;
VBAT_count = 0;
VBAT_SUM = 0;
}
rt_thread_mdelay(5);
}
}
// https://blog.zeruns.com```c
/* Entry function for thread 4, processes data from serial port screen */
static void thread4_HMI_GetDate_entry(void *parameter)
{
HMILCD_Send("CC.x0.val=0"); // Clear current setting value displayed on screen
HMILCD_Send("CV.x0.val=0"); // Clear voltage setting value displayed on screen
HMILCD_Send("CR.x0.val=0"); // Clear resistance setting value displayed on screen
HMILCD_Send("CW.x0.val=0"); // Clear power setting value displayed on screen
while (1)
{
if (Serial3_RxFlag == 1)
{
if (Serial3_RxPacket[0] == 0x01) // Currently on main menu page
{
if (Serial3_RxPacket[1] == 0x10) // Constant current button pressed
{
HMILCD_Send("page CC"); // Switch to constant current mode page
mode = CC; // Set current mode to constant current
}
else if (Serial3_RxPacket[1] == 0x11) // Constant voltage button pressed
{
HMILCD_Send("page CV"); // Switch to constant voltage page
mode = CV; // Set current mode to constant voltage
}
else if (Serial3_RxPacket[1] == 0x12) // Constant resistance button pressed
{
HMILCD_Send("page CR"); // Switch to constant resistance page
mode = CR; // Set current mode to constant resistance
}
else if (Serial3_RxPacket[1] == 0x13) // Constant power button pressed
{
HMILCD_Send("page CW"); // Switch to constant power page
mode = CW; // Set current mode to constant power
}
}
else if (Serial3_RxPacket[0] == 0x02) // Currently on constant current mode page
{
if (Serial3_RxPacket[1] == 0x10) // Menu button pressed
{
HMILCD_Send("CC.t1.txt=\"OFF\""); // Display OFF in title box at top right of screen
HMILCD_Send("CC.b1.txt=\"开启\""); // Display "Turn On" in button at bottom right of screen
Eload_Out = 0; // Set load output status to off
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 outputs high level, turn off constant voltage
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 outputs low level, turn off constant current
PWM_SetCCR4(0); // Set IREF2
HMILCD_Send("page menu"); // Switch to menu page
mode = menu;
}
else if (Serial3_RxPacket[1] == 0x11) // Turn on button pressed and current load output status is off
{
Key_ONOFF = 1;
}
}
else if (Serial3_RxPacket[0] == 0x03) // Currently on constant voltage mode page
{
if (Serial3_RxPacket[1] == 0x10) // Menu button pressed
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 outputs high level, turn off constant voltage
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 outputs low level, turn off constant current
PWM_SetCCR4(0); // Set IREF2
HMILCD_Send("page menu");
mode = menu;
}
if (Serial3_RxPacket[1] == 0x11) // Turn on button pressed and current load output status is off
{
Key_ONOFF = 1;
}
}
else if (Serial3_RxPacket[0] == 0x04) // Currently on constant resistance mode page
{
if (Serial3_RxPacket[1] == 0x10) // Menu button pressed
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 outputs high level, turn off constant voltage
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 outputs low level, turn off constant current
PWM_SetCCR4(0); // Set IREF2
HMILCD_Send("page menu");
mode = menu;
}
if (Serial3_RxPacket[1] == 0x11) // Turn on button pressed and current load output status is off
{
Key_ONOFF = 1;
}
}
else if (Serial3_RxPacket[0] == 0x05) // Currently on constant power mode page
{
if (Serial3_RxPacket[1] == 0x10) // Menu button pressed
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 outputs high level, turn off constant voltage
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 outputs low level, turn off constant current
PWM_SetCCR4(0); // Set IREF2
HMILCD_Send("page menu");
mode = menu;
}
if (Serial3_RxPacket[1] == 0x11) // Turn on button pressed and current load output status is off
{
Key_ONOFF = 1;
}
}
else if (Serial3_RxPacket[0] == 0xAA) // Currently on numeric keypad page
{
char *temp = Serial3_RxPacket;
temp++; // Address increment by 1
uint16_t temp2 = atoi(temp); // Convert string to integer
if (mode == CC)
{
if (temp2 > 1000)
temp2 = 1000;
ISET = temp2 / 100.0;
HMILCD_Send("CC.x0.val=%d", temp2);
if (Eload_Out == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
if (ISET <= 2.5)
{
// Set DAC2 output value to control constant current, +0.5 for rounding
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4(0); // Set IREF2
}
else
{
// Set DAC2 output value to control constant current, +0.5 for rounding
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(ISET / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Set IREF2
}
}
}
else if (mode == CV)
{
VSET = temp2 / 100.0;
HMILCD_Send("CV.x0.val=%d", temp2);
if (Eload_Out == 1)
{
DAC_SetChannel2Data(DAC_Align_12b_R, 4095); // Set IREF1
PWM_SetCCR4(50000); // Set IREF2
if (voltage_dw == 0)
{
DAC_SetChannel1Data(DAC_Align_12b_R,
(uint16_t)(VSET * 0.0325 * 4096 / VREF * DAC1_COMP + 0.5)); // Set DAC1 output value to control constant voltage
}
else if (voltage_dw == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R,
(uint16_t)(VSET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5)); // Set DAC1 output value to control constant voltage
}
else if (voltage_dw == 2)
{
uint16_t vset_pwm = (uint16_t)(VSET * 0.6175 * 4096 / VREF * DAC1_COMP + 0.5);
if (vset_pwm > 4065)
vset_pwm = 4095;
DAC_SetChannel1Data(DAC_Align_12b_R, vset_pwm); // Set DAC1 output value to control constant voltage
}
}
}
else if (mode == CR)
{
RSET = temp2 / 100.0;
HMILCD_Send("CR.x0.val=%d", temp2);
//CR_mode();
}
else if (mode == CW)
{
PSET = temp2 / 100.0;
HMILCD_Send("CW.x0.val=%d", temp2);
//CW_mode();
}
}
Serial3_RxFlag = 0;
}
key123();
rt_thread_mdelay(35);
}
}
``````c
/* Chế độ công suất không đổi */
void CW_mode(void)
{
double Ptemp = PSET / YVF;
if (Ptemp > 10)
Ptemp = 10;
if (Eload_Out == 1)
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(Ptemp / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(Ptemp / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
else
{
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
/* Chế độ điện trở không đổi */
void CR_mode(void)
{
double Rtemp = YVF / RSET;
if (Rtemp > 10)
Rtemp = 10;
if (Eload_Out == 1)
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(Rtemp / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(Rtemp / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
else
{
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
/* Điều khiển PID */
void PID(void)
{
double Ptemp, Rtemp;
if (mode == CC && Eload_Out == 1)
{
qpid_set_dst(&qpid_CC, ISET); // Đặt giá trị mục tiêu PID
I_SET = qpid_cal_pos(&qpid_CC, YIF); // Tính toán PID
if (ISET <= 2.5)
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(I_SET * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
}
else
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(I_SET / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(I_SET / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
}
if (mode == CV && Eload_Out == 1)
{
qpid_set_dst(&qpid_CV, VSET); // Đặt giá trị mục tiêu PID
V_SET = qpid_cal_pos(&qpid_CV, YVF); // Tính toán PID
if (voltage_dw == 0)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(V_SET * 0.0325 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(V_SET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 2)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(V_SET * 0.6175 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
}
if (mode == CW && Eload_Out == 1)
{
qpid_set_dst(&qpid_CW, PSET); // Đặt giá trị mục tiêu PID
P_SET = qpid_cal_pos(&qpid_CW, YIF * YVF); // Tính toán PID
Ptemp = P_SET / YVF;
if (Ptemp > 10)
Ptemp = 10;
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(Ptemp / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(Ptemp / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
if (mode == CR && Eload_Out == 1)
{
qpid_set_dst(&qpid_CR, RSET); // Đặt giá trị mục tiêu PID
R_SET = qpid_cal_pos(&qpid_CR, YVF / YIF); // Tính toán PID
Rtemp = YVF / R_SET;
if (Rtemp > 10)
Rtemp = 10;
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R, (uint16_t)(Rtemp / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(Rtemp / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
}
/* Hàm xử lý phím */
void key123(void)
{
if (key[2] == 1) // Phím 2, phím chuyển đổi
{
if (mode == menu)
{
HMILCD_Send("page CC"); // Chuyển đến trang chế độ dòng điện không đổi
mode = CC; // Đặt chế độ hiện tại là chế độ dòng điện không đổi
}
else if (mode == CC)
{
if (Eload_Out == 1)
{
HMILCD_Send("CC.t1.txt=\"OFF\"");
HMILCD_Send("CC.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
HMILCD_Send("page CV"); // Chuyển đến trang chế độ điện áp không đổi
mode = CV; // Đặt chế độ hiện tại là chế độ điện áp không đổi
}
else if (mode == CV)
{
if (Eload_Out == 1)
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
HMILCD_Send("page CR"); // Chuyển đến trang chế độ điện trở không đổi
mode = CR; // Đặt chế độ hiện tại là chế độ điện trở không đổi
}
else if (mode == CR)
{
if (Eload_Out == 1)
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
HMILCD_Send("page CW"); // Chuyển đến trang chế độ công suất không đổi
mode = CW; // Đặt chế độ hiện tại là chế độ công suất không đổi
}
else if (mode == CW)
{
if (Eload_Out == 1)
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điều khiển điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt điều khiển dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
HMILCD_Send("page menu"); // Chuyển đến trang menu
mode = menu; // Đặt chế độ hiện tại là chế độ menu
}
key[2] = 0;
}
if (key[3] == 1) // Phím 3, phím menu
{
if (Eload_Out == 1)
Key_ONOFF = 1;
rt_thread_mdelay(15);
HMILCD_Send("page menu"); // Chuyển đến trang menu
mode = menu; // Đặt chế độ hiện tại là chế độ menu
key[3] = 0;
}
}
``````c
/* Hàm entry của luồng 5, xử lý phím bật/tắt tải điện tử */
static void thread5_ONOFF_entry(void *parameter)
{
/* Chân LED2 ở chế độ đầu ra */
rt_pin_mode(LED2, PIN_MODE_OUTPUT);
/* Mặc định mức cao */
rt_pin_write(LED2, PIN_HIGH);
while (1)
{
if (Key_ONOFF == 1 | key[1] == 1) // Nút bật được nhấn
{
if (mode == CC) // Chế độ dòng điện không đổi
{
if (Eload_Out == 0) // Khi trạng thái đầu ra tải hiện tại là tắt
{
HMILCD_Send("CC.t1.txt=\"ON\""); // Khung tiêu đề góc trên bên phải màn hình hiển thị ON
HMILCD_Send("CC.b1.txt=\"关闭\""); // Nút góc dưới bên phải màn hình hiển thị tắt
Eload_Out = 1; // Đặt trạng thái đầu ra tải thành bật
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
if (ISET <= 2.5)
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 là để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4(0); // Đặt IREF2
}
else
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 là để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(ISET / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
}
else if (Eload_Out == 1) // Khi trạng thái đầu ra tải hiện tại là bật
{
HMILCD_Send("CC.t1.txt=\"OFF\"");
HMILCD_Send("CC.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
else if (mode == CV) // Chế độ điện áp không đổi
{
if (Eload_Out == 0) // Khi trạng thái đầu ra tải hiện tại là tắt
{
HMILCD_Send("CV.t1.txt=\"ON\"");
HMILCD_Send("CV.b1.txt=\"关闭\"");
Eload_Out = 1;
DAC_SetChannel2Data(DAC_Align_12b_R, 4095); // Đặt IREF1
PWM_SetCCR4(50000); // Đặt IREF2
if (voltage_dw == 0)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.0325 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 2)
{
DAC_SetChannel1Data(DAC_Align_12b_R, (uint16_t)(VSET * 0.6175 * 4096 / VREF * DAC1_COMP + 0.5));
// Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
}
else if (Eload_Out == 1) // Khi trạng thái đầu ra tải hiện tại là bật
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
else if (mode == CR) // Chế độ điện trở không đổi
{
if (Eload_Out == 0) // Khi trạng thái đầu ra tải hiện tại là tắt
{
HMILCD_Send("CR.t1.txt=\"ON\"");
HMILCD_Send("CR.b1.txt=\"关闭\"");
Eload_Out = 1;
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
CR_mode();
}
else if (Eload_Out == 1) // Khi trạng thái đầu ra tải hiện tại là bật
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
else if (mode == CW) // Chế độ công suất không đổi
{
if (Eload_Out == 0) // Khi trạng thái đầu ra tải hiện tại là tắt
{
HMILCD_Send("CW.t1.txt=\"ON\"");
HMILCD_Send("CW.b1.txt=\"关闭\"");
Eload_Out = 1;
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
CW_mode();
}
else if (Eload_Out == 1) // Khi trạng thái đầu ra tải hiện tại là bật
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"开启\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt dòng điện không đổi
PWM_SetCCR4(0); // Đặt IREF2
}
}
Key_ONOFF = 0;
key[1] = 0;
}
if (Eload_Out == 0)
{
rt_pin_write(LED2, SET);
}
else if (Eload_Out == 1)
{
rt_pin_write(LED2, RESET);
}
rt_thread_mdelay(35);
}
}
/* Hàm entry của luồng 7, hiển thị tham số trên màn hình nối tiếp */
static void thread7_HMI_Display_entry(void *parameter)
{
while (1)
{
if (mode != menu)
{
double V = lowV1(YVF);
double I = lowV2(YIF);
HMILCD_Send("x1.val=%d", (uint16_t)(V * 100)); // Hiển thị điện áp
HMILCD_Send("x2.val=%d", (uint16_t)(I * 1000)); // Hiển thị dòng điện
HMILCD_Send("x3.val=%d", (uint32_t)(I * V * 100)); // Hiển thị công suất
HMILCD_Send("x4.val=%d", (uint32_t)(V / I * 100)); // Hiển thị điện trở
HMILCD_Send("x5.val=%d", (uint32_t)(VBAT * 100)); // Hiển thị điện trở
}
rt_thread_mdelay(50);
}
}
/* Hàm entry của luồng 8, điều khiển quạt tản nhiệt */
static void thread8_FAN_entry(void *parameter)
{
while (1)
{
uint16_t P = (uint16_t)(YIF * YVF + 0.5);
if (P >= 13) // Khởi động quạt khi công suất lớn hơn 13W
{
FAN_PWM_ON();
if (P < 20)
{
FAN_PWM_SetCCR(20); // Điều khiển quạt với chu kỳ công việc 20%
}
else if (P >= 20 && P < 25)
{
FAN_PWM_SetCCR(30);
}
else if (P >= 25 && P < 30)
{
FAN_PWM_SetCCR(40);
}
else if (P >= 30 && P < 35)
{
FAN_PWM_SetCCR(50);
}
else if (P >= 35 && P < 40)
{
FAN_PWM_SetCCR(60);
}
else if (P >= 40 && P < 45)
{
FAN_PWM_SetCCR(70);
}
else if (P >= 45 && P < 50)
{
FAN_PWM_SetCCR(80);
}
else if (P >= 50 && P < 60)
{
FAN_PWM_SetCCR(90);
}
else if (P >= 60)
{
FAN_PWM_SetCCR(100);
}
}
else if (P <= 8)
{
FAN_PWM_SetCCR(0); // Tắt đầu ra PWM của quạt và xuất mức thấp
FAN_PWM_OFF();
}
rt_thread_mdelay(200);
}
}
/* Hàm entry của luồng 9, điều khiển chế độ công suất không đổi và điện trở không đổi */
static void thread9_CWCR_entry(void *parameter)
{
while (1)
{
if (mode == CW)
{
CW_mode();
}
if (mode == CR)
{
CR_mode();
}
rt_thread_mdelay(50);
}
}
```/* Hàm entry của thread 10, xử lý dữ liệu được gửi từ Bluetooth */
static void thread10_BlueTooth_entry(void *parameter)
{
HMILCD_Send("CC.x0.val=0"); // Xóa giá trị thiết lập dòng điện hiển thị trên màn hình
HMILCD_Send("CV.x0.val=0"); // Xóa giá trị thiết lập điện áp hiển thị trên màn hình
HMILCD_Send("CR.x0.val=0"); // Xóa giá trị thiết lập điện trở hiển thị trên màn hình
HMILCD_Send("CW.x0.val=0"); // Xóa giá trị thiết lập công suất hiển thị trên màn hình
while (1)
{
if (Serial5_RxFlag == 1)
{
if (Serial5_RxPacket[0] == 0x01) // Hiện tại là trang menu chính
{
if (Serial5_RxPacket[1] == 0x10) // Nút dòng điện không đổi được nhấn
{
if (mode == CV)
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"Bật\"");
}
else if (mode == CR)
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"Bật\"");
}
else if (mode == CW)
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"Bật\"");
}
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
Eload_Out = 0;
HMILCD_Send("page CC"); // Chuyển đến trang chế độ dòng điện không đổi
mode = CC; // Thiết lập chế độ hiện tại là dòng điện không đổi
}
else if (Serial5_RxPacket[1] == 0x11) // Nút điện áp không đổi được nhấn
{
if (mode == CC)
{
HMILCD_Send("CC.t1.txt=\"OFF\"");
HMILCD_Send("CC.b1.txt=\"Bật\"");
}
else if (mode == CR)
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"Bật\"");
}
else if (mode == CW)
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"Bật\"");
}
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
Eload_Out = 0;
HMILCD_Send("page CV"); // Chuyển đến trang điện áp không đổi
mode = CV; // Thiết lập chế độ hiện tại là điện áp không đổi
}
else if (Serial5_RxPacket[1] == 0x12) // Nút điện trở không đổi được nhấn
{
if (mode == CC)
{
HMILCD_Send("CC.t1.txt=\"OFF\"");
HMILCD_Send("CC.b1.txt=\"Bật\"");
}
else if (mode == CV)
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"Bật\"");
}
else if (mode == CW)
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"Bật\"");
}
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
Eload_Out = 0;
HMILCD_Send("page CR"); // Chuyển đến trang điện trở không đổi
mode = CR; // Thiết lập chế độ hiện tại là điện trở không đổi
}
else if (Serial5_RxPacket[1] == 0x13) // Nút công suất không đổi được nhấn
{
if (mode == CV)
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"Bật\"");
}
else if (mode == CR)
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"Bật\"");
}
else if (mode == CC)
{
HMILCD_Send("CC.t1.txt=\"OFF\"");
HMILCD_Send("CC.b1.txt=\"Bật\"");
}
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
Eload_Out = 0;
HMILCD_Send("page CW"); // Chuyển đến trang công suất không đổi
mode = CW; // Thiết lập chế độ hiện tại là công suất không đổi
}
}
else if (Serial5_RxPacket[0] == 0x08) // Quay lại menu
{
if (mode == CC)
{
HMILCD_Send("CC.t1.txt=\"OFF\""); // Khung tiêu đề góc trên bên phải màn hình hiển thị OFF
HMILCD_Send("CC.b1.txt=\"Bật\""); // Nút góc dưới bên phải màn hình hiển thị Bật
Eload_Out = 0; // Thiết lập trạng thái xuất tải là tắt
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
HMILCD_Send("page menu"); // Chuyển đến trang menu
mode = menu;
}
else if (mode == CV)
{
HMILCD_Send("CV.t1.txt=\"OFF\"");
HMILCD_Send("CV.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
HMILCD_Send("page menu");
mode = menu;
}
else if (mode == CR)
{
HMILCD_Send("CR.t1.txt=\"OFF\"");
HMILCD_Send("CR.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
HMILCD_Send("page menu");
mode = menu;
}
else if (mode == CW)
{
HMILCD_Send("CW.t1.txt=\"OFF\"");
HMILCD_Send("CW.b1.txt=\"Bật\"");
Eload_Out = 0;
DAC_SetChannel1Data(DAC_Align_12b_R, 4095); // DAC1 xuất mức cao, tắt chế độ điện áp không đổi
DAC_SetChannel2Data(DAC_Align_12b_R, 0); // DAC2 xuất mức thấp, tắt chế độ dòng điện không đổi
PWM_SetCCR4(0); // Thiết lập IREF2
HMILCD_Send("page menu");
mode = menu;
}
}
else if (Serial5_RxPacket[0] == 0x09) // Nút bật
{
Key_ONOFF = 1;
}
else if (Serial5_RxPacket[0] == 0xAA) // Hiện tại là trang bàn phím số
{
char *temp = Serial5_RxPacket;
temp++; // Địa chỉ tự tăng 1
uint16_t temp2 = atoi(temp); // Chuyển đổi chuỗi thành số nguyên
if (mode == CC)
{
if (temp2 > 1000)
temp2 = 1000;
ISET = temp2 / 100.0;
HMILCD_Send("CC.x0.val=%d", temp2);```c
if (Eload_Out == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R, 0);
if (ISET <= 2.5)
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 là để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4(0); // Đặt IREF2
}
else
{
// Đặt giá trị đầu ra DAC2, điều khiển dòng điện không đổi, +0.5 là để làm tròn
DAC_SetChannel2Data(DAC_Align_12b_R,
(uint16_t)(ISET / 2.0 * 0.01 * 50 * 4096 / VREF * DAC2_COMP + 0.5));
PWM_SetCCR4((uint16_t)(ISET / 2.0 * 0.01 * 50 / VCC * 50000 * IREF2_COMP + 0.5)); // Đặt IREF2
}
}
}
else if (mode == CV)
{
VSET = temp2 / 100.0;
HMILCD_Send("CV.x0.val=%d", temp2);
if (Eload_Out == 1)
{
DAC_SetChannel2Data(DAC_Align_12b_R, 4095); // Đặt IREF1
PWM_SetCCR4(50000); // Đặt IREF2
if (voltage_dw == 0)
{
DAC_SetChannel1Data(DAC_Align_12b_R,
(uint16_t)(VSET * 0.0325 * 4096 / VREF * DAC1_COMP + 0.5)); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 1)
{
DAC_SetChannel1Data(DAC_Align_12b_R,
(uint16_t)(VSET * 0.0947 * 4096 / VREF * DAC1_COMP + 0.5)); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
else if (voltage_dw == 2)
{
uint16_t vset_pwm = (uint16_t)(VSET * 0.6175 * 4096 / VREF * DAC1_COMP + 0.5);
if (vset_pwm > 4065)
vset_pwm = 4095;
DAC_SetChannel1Data(DAC_Align_12b_R, vset_pwm); // Đặt giá trị đầu ra DAC1, điều khiển điện áp không đổi
}
}
}
else if (mode == CR)
{
RSET = temp2 / 100.0;
HMILCD_Send("CR.x0.val=%d", temp2);
CR_mode();
}
else if (mode == CW)
{
PSET = temp2 / 100.0;
HMILCD_Send("CW.x0.val=%d", temp2);
CW_mode();
}
}
Serial5_RxFlag = 0;
}
rt_thread_mdelay(40);
}
}
Đọc thêm
- Khuyến nghị VPS/máy chủ đám mây giá rẻ và hiệu suất cao: https://blog.zeruns.com/archives/383.html
- Hướng dẫn mở máy chủ Minecraft: https://blog.zeruns.com/tag/mc/
- Xây dựng trang web blog mà không cần mã! Hướng dẫn xây dựng blog cá nhân cực kỳ chi tiết: https://blog.zeruns.com/archives/783.html
- Hướng dẫn xây dựng máy chủ xuyên mạng nội bộ, hướng dẫn xây dựng và sử dụng NPS: https://blog.zeruns.com/archives/741.html
- Hướng dẫn xây dựng SD (Stable Diffusion) trên máy chủ GPU đám mây Yun, xây dựng trang web vẽ AI của riêng bạn: https://blog.zeruns.com/archives/768.html
- Đánh giá mở hộp đơn giản của công tắc 2.5G TL-SE2109, 8 cổng điện 2.5G + 1 cổng quang 10G (SFP+): https://blog.zeruns.com/archives/780.html















