修改通讯串口逻辑,添加810,811,812指令

This commit is contained in:
sc committed 2025-10-28 01:09:33 +08:00
1 parent 64d820b24c
commit 155358f5d0
42 files changed
+17864 -579

No files matched your search

+149 -58
View File
@@ -23,6 +23,9 @@ rt_mq_t proc_mq;
char cjson_falg=0;//是否解析cjson
char *json_buffer=NULL;
//
/**
* 截取两个指定子串之间的内容
* @param src 源字符串
@@ -117,58 +120,63 @@ void pasre_DAT(const char *api, const char *json_str)
}
else if (strcmp(api, "SC810") == 0)
{
char STime[25];
char pTime[10];
char Work_[25];
char Dye_[25];
char STime_[25];
char pTime_[10];
// 字符串赋值
GET_STRING(Work, root, "Work", sizeof(Work));
GET_STRING(Dye, root, "Dye", sizeof(Dye));
GET_STRING(STime, root, "STime", sizeof(STime));
GET_STRING(pTime, root, "Time", sizeof(pTime));
GET_STRING(Work_, root, "Work", sizeof(Work_));
GET_STRING(Dye_, root, "Dye", sizeof(Dye_));
GET_STRING(STime_, root, "STime", sizeof(STime_));
GET_STRING(pTime_, root, "Time", sizeof(pTime_));
// 定义足够大的缓冲区
char sql[512] = {0}; // 初始化为 0
// 安全格式化
rt_snprintf(sql, sizeof(sql),
"INSERT INTO WorkorderSteps(WorkOrder,DYELOT,ReDye,StartTime,Time)"
"VALUES('%s','%s',0,%s,%s,)",
Work, Dye, STime,pTime);
"INSERT INTO WorkOrder(WorkOrder,DYELOT,ReDye,StartTime,Time)"
"VALUES('%s','%s',0,'%s','%s')",
Work_, Dye_, STime_,pTime_);
if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) //
{
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(Redye));
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work_));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(0));
}
}
else if (strcmp(api, "SC811") == 0)
{//工单明细
char Work_[25];
char Dye_[25];
char StepID_[4];
char SIDS1_[4];
int StepN_;
int P1_;
int P2_;
int P3_;
int P4_;
int P5_;
int P1S1_;
int P2S1_;
int P3S1_;
int P4S1_;
int P5S1_;
// 字符串赋值
GET_STRING(Work, root, "Work", sizeof(Work));
GET_STRING(Dye, root, "Dye", sizeof(Dye));
GET_STRING(StepID, root, "StepID", sizeof(StepID));
GET_STRING(SIDS1, root, "SIDS1", sizeof(SIDS1));
//GET_STRING(SIDS2, root, "SIDS2", sizeof(SIDS2));
//GET_STRING(SIDS3, root, "SIDS3", sizeof(SIDS3));
GET_STRING(Work_, root, "Work", sizeof(Work_));
GET_STRING(Dye_, root, "Dye", sizeof(Dye_));
GET_STRING(StepID_, root, "StepID", sizeof(StepID_));
GET_STRING(SIDS1_, root, "SIDS1", sizeof(SIDS1_));
//整数
GET_INT_FROM_ANY(StepN, root, "Step", 0);
GET_INT_FROM_ANY(P1, root, "P1", 0);
GET_INT_FROM_ANY(P2, root, "P2", 0);
GET_INT_FROM_ANY(P3, root, "P3", 0);
GET_INT_FROM_ANY(P4, root, "P4", 0);
GET_INT_FROM_ANY(P5, root, "P5", 0);
GET_INT_FROM_ANY(P1S1, root, "P1S1",0);
GET_INT_FROM_ANY(P2S1, root, "P2S1",0);
GET_INT_FROM_ANY(P3S1, root, "P3S1",0);
GET_INT_FROM_ANY(P4S1, root, "P4S1",0);
GET_INT_FROM_ANY(P5S1, root, "P5S1",0);
//GET_INT_FROM_ANY(P1S2, root, "P1S2",0);
//GET_INT_FROM_ANY(P2S2, root, "P2S2",0);
//GET_INT_FROM_ANY(P3S2, root, "P3S2",0);
//GET_INT_FROM_ANY(P4S2, root, "P4S2",0);
//GET_INT_FROM_ANY(P5S2, root, "P5S2",0);
//GET_INT_FROM_ANY(P1S3, root, "P1S3",0);
//GET_INT_FROM_ANY(P2S3, root, "P2S3",0);
//GET_INT_FROM_ANY(P3S3, root, "P3S3",0);
//GET_INT_FROM_ANY(P4S3, root, "P4S3",0);
//GET_INT_FROM_ANY(P5S3, root, "P5S3",0);
GET_INT_FROM_ANY(StepN_, root, "Step", 0);
GET_INT_FROM_ANY(P1_, root, "P1", 0);
GET_INT_FROM_ANY(P2_, root, "P2", 0);
GET_INT_FROM_ANY(P3_, root, "P3", 0);
GET_INT_FROM_ANY(P4_, root, "P4", 0);
GET_INT_FROM_ANY(P5_, root, "P5", 0);
GET_INT_FROM_ANY(P1S1_, root, "P1S1",0);
GET_INT_FROM_ANY(P2S1_, root, "P2S1",0);
GET_INT_FROM_ANY(P3S1_, root, "P3S1",0);
GET_INT_FROM_ANY(P4S1_, root, "P4S1",0);
GET_INT_FROM_ANY(P5S1_, root, "P5S1",0);
// 定义足够大的缓冲区
char sql[512] = {0}; // 初始化为 0
@@ -176,41 +184,124 @@ void pasre_DAT(const char *api, const char *json_str)
// 安全格式化
rt_snprintf(sql, sizeof(sql),
"INSERT INTO WorkorderSteps(WorkOrder,DYELOT,ReDye,Step,StepID,P1,P2,P3,P4,P5,StepID_S1,P1_S1,P2_S1,P3_S1,P4_S1,P5_S1)"
"VALUES('%s','%s',0,%d,%s,%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d)",
Work, Dye, StepN,StepID,P1, P2, P3, P4, P5,SIDS1,P1S1,P2S1,P3S1,P4S1,P5S1 );
"VALUES('%s','%s',0,%d,'%s',%d,%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d)",
Work_, Dye_, StepN_,StepID_,P1_, P2_, P3_, P4_, P5_,SIDS1_,P1S1_,P2S1_,P3S1_,P4S1_,P5S1_ );
if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) //
{
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(Redye));
cJSON_AddItemToObject(dat,"Step",cJSON_CreateNumber(StepN));
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work_));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(0));
cJSON_AddItemToObject(dat,"Step",cJSON_CreateNumber(StepN_));
}
}
else if (strcmp(api, "SC812") == 0) {
//工单设定
else if (strcmp(api, "SC812") == 0)
{//工单设定
char Work_[25];
int Pump_;
int Blower_;
int ClothWheel_;
int Swing_;
int Nozzle_;
// 字符串赋值
GET_STRING(Work_, root, "WorkOrder", sizeof(Work_));
//整数
GET_INT_FROM_ANY(Pump_, root, "PumpSpeed", 0);
GET_INT_FROM_ANY(Blower_, root, "Blower", 0);
GET_INT_FROM_ANY(ClothWheel_, root, "ClothWheel", 0);
GET_INT_FROM_ANY(Swing_, root, "Swing", 0);
GET_INT_FROM_ANY(Nozzle_, root, "Nozzle", 0);
// 定义足够大的缓冲区
char sql[512] = {0}; // 初始化为 0
// 安全格式化
rt_snprintf(sql, sizeof(sql),
"INSERT OR IGNORE INTO WorkOrderSet(WorkOrder,ReDye,PumpSpeed,Blower,ClothWheel,Swing,Nozzle)"
"VALUES('%s',0,%d,%d,%d,%d,%d)",
Work_, Pump_,Blower_,ClothWheel_, Swing_, Nozzle_);
if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) //
{
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work_));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(0));
}
}
else if (strcmp(api, "SC813") == 0) {
printf("Processing:SC813\n");
else if (strcmp(api, "SC813") == 0)
{//领料单插入
char Work_[25];
char Dye_[25];
char ProductCode_[15];
char ProductName_[15];
char Grams_[8];
int ProductType_;
int StepN_;
//字符
GET_STRING(Work_, root, "Work", sizeof(Work_));
GET_STRING(Dye_, root, "Dye", sizeof(Dye_));
GET_STRING(ProductName_, root, "ProductName", sizeof(ProductName_));
GET_STRING(ProductCode_, root, "ProductCode", sizeof(ProductCode_));
GET_STRING(Grams_, root, "Grams", sizeof(Grams_));
//整数
GET_INT_FROM_ANY(StepN_, root, "Step", 0);
GET_INT_FROM_ANY(ProductType_, root, "ProductType", 0);
// 定义足够大的缓冲区
char sql[512] = {0}; // 初始化为 0
// 安全格式化
rt_snprintf(sql, sizeof(sql),
"INSERT OR IGNORE INTO Dyelot(WorkOrder,Dyelot,ReDye,Step,ProductCode,ProductName,ProductType,Grams)"
"VALUES('%s','%s',0,%d,%s,%s,%d,%s)",
Work_, Dye_,StepN_,ProductCode_,ProductName_ ,ProductType_,Grams_);
if( db_send_command(DB_CMD_EXEC, sql, 500)==RT_EOK) //
{
cJSON_AddItemToObject(dat,"Work",cJSON_CreateString(Work_));
cJSON_AddItemToObject(dat,"Dye",cJSON_CreateString(Dye_));
cJSON_AddItemToObject(dat,"ReDye",cJSON_CreateNumber(0));
cJSON_AddItemToObject(dat,"Step",cJSON_CreateNumber(StepN_));
}
}
else if (strcmp(api, "SC820") == 0) {
printf("Processing:SC820\n");
else if (strcmp(api, "SC820") == 0)
{//设置系统时间
char Time_[25];
GET_STRING(Time_, root, "Work", sizeof(Time_));
cJSON_AddItemToObject(dat,"time",cJSON_CreateString("systime"));
}
else if (strcmp(api, "SC821") == 0) {
else if (strcmp(api, "SC821") == 0)
{
printf("Processing:SC821\n");
}
else if (strcmp(api, "SC822") == 0) {
else if (strcmp(api, "SC822") == 0)
{
printf("Processing:SC822\n");
}
else if (strcmp(api, "SC827") == 0) {
else if (strcmp(api, "SC827") == 0)
{
printf("Processing:SC827\n");
}
else if (strcmp(api, "SC828") == 0) {
else if (strcmp(api, "SC828") == 0)
{
printf("Processing:SC828\n");
}
else if (strcmp(api, "SC829") == 0) {
printf("Processing:SC829\n");
else if (strcmp(api, "SC829") == 0)
{//锁定自动
char NAME_[4];
char VALUE_[4];
GET_STRING(NAME_, root, "NAME", sizeof(NAME_));
GET_STRING(VALUE_, root, "VALUE", sizeof(VALUE_));
if (strcmp(NAME_, "LOCK") == 0) {
if (strcmp(VALUE_, "True") == 0)
{MACHINE_LOCK=1;}else{MACHINE_LOCK=0;}
}
if (strcmp(NAME_, "AUTO") == 0) {
if (strcmp(VALUE_, "True") == 0)
{MACHINE_AUTO=1;}else{MACHINE_AUTO=0;}
}
cJSON_AddItemToObject(dat,"NAME",cJSON_CreateString(NAME_));
cJSON_AddItemToObject(dat,"VALUE",cJSON_CreateString(VALUE_));
}
else if (strcmp(api, "SC830") == 0) {
//当前信息
else if (strcmp(api, "SC830") == 0)
{//当前信息
cJSON_AddItemToObject(dat,"ERR",cJSON_CreateBool(MACHINE_ERR));
cJSON_AddItemToObject(dat,"LOCK",cJSON_CreateBool(MACHINE_LOCK));
cJSON_AddItemToObject(dat,"Status",cJSON_CreateString(Message));
@@ -382,7 +473,7 @@ int data_comm_init(void)
}
rt_thread_t tid = rt_thread_create("data_comm", proc_thread_entry, RT_NULL,
1024*4, 20, 10);
1024*6, 20, 10);
if (tid != RT_NULL)
{
rt_thread_startup(tid);
+34 -7
View File
@@ -133,15 +133,42 @@ static rt_err_t uart_rx_ind(rt_device_t dev, rt_size_t size)
return RT_EOK;
}
// 从环形缓冲区提取一行
// 从环形缓冲区提取一行rt_kprintf("%s\n",buf);
static int get_line(char *buf, int maxlen)
{
int len = rt_ringbuffer_get(&rx_rb, (rt_uint8_t*)buf, maxlen - 1);
if (len > 0) {
buf[len] = '\0';
return len;
}
return 0;
int len = 0;
rt_uint8_t ch;
// 逐字节读取,直到遇到 '\n' 或缓冲区满
while (len < maxlen - 1)
{
// 从环形缓冲区读一个字节
if (rt_ringbuffer_getchar(&rx_rb, &ch) == 0)
{
// 缓冲区为空,无数据可读
break;
}
buf[len++] = ch;
// 检查是否为行结束符
if (ch == '\n')
{
buf[len] = '\0'; // 添加字符串结束符
return len; // 返回完整行长度
}
}
// 如果没有遇到 '\n',说明不是完整的一行
// 我们可以选择:把已读的数据放回 ringbuffer,或丢弃(推荐放回)
// 这里选择:把所有读取的字符重新放回 ringbuffer
if (len > 0)
{
// 将已读取但未构成完整行的数据放回 ringbuffer 开头
rt_ringbuffer_put(&(rx_rb), (rt_uint8_t*)buf, len);
}
return 0; // 未收到完整行,返回 0
}
// 启动 UART 线程
+1
View File
@@ -13,6 +13,7 @@ char machine_ID[3] = "23";
// 状态标志
char MACHINE_ERR = 0;
char MACHINE_LOCK = 0;
char MACHINE_AUTO = 0;
char MACHINE_CALL = 0;
char MACHINE_USER = 0;
+1
View File
@@ -13,6 +13,7 @@ extern char machine_ID[3];
// ===== 布尔变量 =====
extern char MACHINE_ERR;
extern char MACHINE_LOCK;
extern char MACHINE_AUTO;
extern char MACHINE_CALL;
extern char MACHINE_USER;
+59 -46
View File
@@ -17,7 +17,7 @@
#define DB_NAME "/SC828.db"
int db_HelperInit;
rt_mq_t db_mq = RT_NULL; //
sqlite3 **db;
sqlite3 *db;
// 消息队列对象与缓冲区(静态分配)
//static struct rt_mq db_mq;
@@ -45,7 +45,7 @@ static const char *sql_upgrade_workorder_set =
"CREATE TABLE WorkOrderSet (WorkOrder VARCHAR,ReDye INT DEFAULT (0),PumpSpeed INT,Blower INT,Swing INT,ClothWheel INT,Nozzle INT); ";
static const char *sql_upgrade_workorder =
"CREATE TABLE WorkOrder (WorkOrder VARCHAR,Dyelot VARCHAR,ReDyeINT DEFAULT (0),ProgramNameVARCHAR,StartTime DATETIME,EndTime DATETIME,"
"CREATE TABLE WorkOrder (WorkOrder VARCHAR,Dyelot VARCHAR,ReDye INT DEFAULT (0),ProgramName VARCHAR,StartTime DATETIME,EndTime DATETIME,"
"Time TEXT,lock INT,State INT,ProgramID VARCHAR,Machines VARCHAR,color VARCHAR,ColorNumber VARCHAR,Client VARCHAR,ClothWeight VARCHAR,"
"ClothSpecies VARCHAR,BathRatio VARCHAR,Total VARCHAR,USER VARCHAR,ColorName VARCHAR,Remark TEXT); ";
@@ -183,54 +183,67 @@ void close_db_immediately(void) {
void db_sqlite_init_full(void)
{
if (access(DB_NAME, F_OK) == 0)
{//打开文件
if (sqlite3_open(DB_NAME, &db) == 0)
{
rt_kprintf("DB open\n");
if (db_connect(DB_NAME) == RT_EOK){
if(db_table_is_exist("WorkorderSteps")<=0){
if(db_create_database(sql_upgrade_workorder_steps)==0)
{rt_kprintf("WorkorderSteps Created successfully \n");}else{rt_kprintf("WorkorderSteps Creation failed \n");}
}
if(db_table_is_exist("WorkOrderSet")<=0){
if(db_create_database(sql_upgrade_workorder_set)==0)
{rt_kprintf("WorkOrderSet Created successfully \n");}else{rt_kprintf("WorkOrderSet Creation failed \n");}
}
if(db_table_is_exist("WorkOrder")<=0){
if(db_create_database(sql_upgrade_workorder)==0)
{rt_kprintf("WorkOrder Created successfully \n");}else{rt_kprintf("WorkOrder Creation failed \n");}
}
if(db_table_is_exist("RUN")<=0){
if(db_create_database(sql_upgrade_run_table)==0)
{rt_kprintf("RUN Created successfully \n");}else{rt_kprintf("RUN Creation failed \n");}
}
if(db_table_is_exist("Dyelot")<=0){
if(db_create_database(sql_upgrade_dyelot_table)==0)
{rt_kprintf("Dyelot Created successfully \n");}else{rt_kprintf("Dyelot Creation failed \n");}
}
if(db_table_is_exist("IOLog")<=0){
if(db_create_database(sql_upgrade_iolog_table)==0)
{rt_kprintf("IOLog Created successfully \n");}else{rt_kprintf("IOLog Creation failed \n");}
}
if(db_table_is_exist("Chart")<=0){
if(db_create_database(sql_upgrade_chart_table)==0)
{rt_kprintf("Chart Created successfully \n");}else{rt_kprintf("Chart Creation failed \n");}
}
}else{
rt_kprintf("DB ok\n");
db_connect(DB_NAME);
rt_kprintf("[DataBASE]DB open\n");
//检查表格
if(db_table_is_exist("WorkorderSteps")==0){
rt_kprintf("[DataBASE]WorkorderSteps not exist \n");
if(sqlite3_exec(db,sql_upgrade_workorder_steps, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkorderSteps Created successfully \n");}else{rt_kprintf("[DataBASE]WorkorderSteps Creation failed \n");}
}
if(db_table_is_exist("WorkOrderSet")==0){
rt_kprintf("[DataBASE]WorkOrderSet not exist \n");
if(sqlite3_exec(db,sql_upgrade_workorder_set, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkOrderSet Created successfully \n");}else{rt_kprintf("[DataBASE]WorkOrderSet Creation failed \n");}
}
if(db_table_is_exist("WorkOrder")==0){
rt_kprintf("[DataBASE]WorkOrder not exist \n");
if(sqlite3_exec(db,sql_upgrade_workorder, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkOrder Created successfully \n");}else{rt_kprintf("[DataBASE]WorkOrder Creation failed \n");}
}
if(db_table_is_exist("RUN")==0){
rt_kprintf("[DataBASE]RUN not exist \n");
if(sqlite3_exec(db,sql_upgrade_run_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]RUN Created successfully \n");}else{rt_kprintf("[DataBASE]RUN Creation failed \n");}
}
if(db_table_is_exist("Dyelot")==0){
rt_kprintf("[DataBASE]Dyelot not exist \n");
if(sqlite3_exec(db,sql_upgrade_dyelot_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]Dyelot Created successfully \n");}else{rt_kprintf("[DataBASE]Dyelot Creation failed \n");}
}
if(db_table_is_exist("IOLog")==0){
rt_kprintf("[DataBASE]IOLog not exist \n");
if(sqlite3_exec(db,sql_upgrade_iolog_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]IOLog Created successfully \n");}else{rt_kprintf("[DataBASE]IOLog Creation failed \n");}
}
if(db_table_is_exist("Chart")==0){
rt_kprintf("[DataBASE]Chart not exist \n");
if(sqlite3_exec(db,sql_upgrade_chart_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]Chart Created successfully \n");}else{rt_kprintf("[DataBASE]Chart Creation failed \n");}
}
}else{
rt_kprintf("DB open failed \n");
sqlite3_open(DB_NAME, db);
//创建表
db_create_database(sql_upgrade_workorder_steps);
db_create_database(sql_upgrade_workorder_set);
db_create_database(sql_upgrade_workorder);
db_create_database(sql_upgrade_run_table);
db_create_database(sql_upgrade_dyelot_table);
db_create_database(sql_upgrade_iolog_table);
db_create_database(sql_upgrade_chart_table);
rt_kprintf("[DataBASE]DB not open\n");
}
}else{
rt_kprintf("DB open failed \n");
sqlite3_open(DB_NAME, &db);
if(sqlite3_exec(db,sql_upgrade_workorder_steps, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkorderSteps Created successfully \n");}else{rt_kprintf("[DataBASE]WorkorderSteps Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_workorder_set, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkOrderSet Created successfully \n");}else{rt_kprintf("[DataBASE]WorkOrderSet Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_workorder, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]WorkOrder Created successfully \n");}else{rt_kprintf("[DataBASE]WorkOrder Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_run_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]RUN Created successfully \n");}else{rt_kprintf("[DataBASE]RUN Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_dyelot_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]Dyelot Created successfully \n");}else{rt_kprintf("[DataBASE]Dyelot Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_iolog_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]IOLog Created successfully \n");}else{rt_kprintf("[DataBASE]IOLog Creation failed \n");}
if(sqlite3_exec(db,sql_upgrade_chart_table, 0, 0, 0)==0)
{rt_kprintf("[DataBASE]Chart Created successfully \n");}else{rt_kprintf("[DataBASE]Chart Creation failed \n");}
}
}
/**
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-10-27 Administrator the first version
*/
#include "lvgl.h"
#include "lv_port_disp.h"
#include "ssd1963.h"
// 屏幕分辨率(请根据实际 LCD 调整)
#define LCD_WIDTH 480
#define LCD_HEIGHT 272
// 绘图缓冲区:建议为屏幕宽度 * 10 行
static lv_color_t draw_buf1[LCD_WIDTH * 10]; // 前缓冲
static lv_color_t draw_buf2[LCD_WIDTH * 10]; // 后缓冲(可选,用于双缓冲)
// LVGL 绘图缓冲区描述符
static lv_disp_draw_buf_t draw_buf;
// 刷屏完成回调
static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
// 设置 SSD1963 显示窗口
ssd1963_set_window(area->x1, area->y1, area->x2, area->y2);
// 写入像素数据
uint32_t size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1);
for (uint32_t i = 0; i < size; i++) {
SSD1963_DATA_ADDR = color_p[i].full; // 使用 FSMC 写入
}
// ✅ 必须调用!通知 LVGL 刷屏已完成
lv_disp_flush_ready(disp_drv);
}
/**
* @brief 初始化 LVGL 显示驱动
*/
void lv_port_disp_init(void)
{
// 1. 初始化 FSMC 总线(由 STM32CubeMX 生成)
// MX_FSMC_Init();
// 2. 初始化 SSD1963 控制器
ssd1963_init(); // ✅ 使用 ssd1963.h 中的初始化函数
// 注释掉重复的 lcd_init()
// lcd_init(); // ❌ 删除:与 ssd1963_init() 重复或冲突
// 3. 初始化 LVGL 的绘图缓冲区
// 参数:缓冲区结构体、第一个缓冲区、第二个缓冲区(可选)、总大小(像素数)
lv_disp_draw_buf_init(&draw_buf, draw_buf1, draw_buf2, LCD_WIDTH * 10);
// 4. 初始化显示驱动
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LCD_WIDTH; // 水平分辨率
disp_drv.ver_res = LCD_HEIGHT; // 垂直分辨率
disp_drv.flush_cb = disp_flush; // 刷屏回调
disp_drv.draw_buf = &draw_buf; // 绑定缓冲区 ✅ 必须赋值!
// 5. 注册显示设备到 LVGL
lv_disp_drv_register(&disp_drv);
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-10-27 Administrator the first version
*/
#ifndef APPLICATIONS_LV_PORT_DISP_H_
#define APPLICATIONS_LV_PORT_DISP_H_
#ifdef __cplusplus
extern "C" {
#endif
#define LV_COLOR_DEPTH 16
#define LV_HOR_RES_MAX 480
#define LV_VER_RES_MAX 272
#define LV_DPI 130
void ssd1963_init(void);
void ssd1963_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
/**
* @brief 初始化 LVGL 显示驱动
* 调用 ssd1963_init() 并注册到 LVGL
*/
void lv_port_disp_init(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* APPLICATIONS_LV_PORT_DISP_H_ */
+248
View File
@@ -0,0 +1,248 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-10-26 Administrator the first version
*/
/**
* @file ssd1963.c
* @brief SSD1963 TFT LCD Controller Driver for STM32F407 + FSMC + RT-Thread
* @author Qwen (Generated for RTT)
* @date 2025-10-26
*/
#include "rtthread.h"
#include "rtdevice.h"
#include "ssd1963.h" // 确保路径正确
#include <board.h>
// ==================== 引脚定义 (根据你的硬件修改) ====================
#define LCD_RST_PIN GET_PIN(B,2) // 复位引脚
#define LCD_BL_PIN GET_PIN(B,0) // 背光控制引脚 (PWM)
// ==================== SSD1963 命令定义 ====================
#define SSD1963_NOP 0x00
#define SSD1963_SOFT_RESET 0x01
#define SSD1963_GET_PWR_MODE 0x0A
#define SSD1963_GET_ADDR_MODE 0x0B
#define SSD1963_GET_PIX_FORMAT 0x0C
#define SSD1963_GET_SIG_MODE 0x0D
#define SSD1963_GET_DIAGNOSTIC 0x0F
#define SSD1963_ENTER_SLEEP 0x10
#define SSD1963_EXIT_SLEEP 0x11
#define SSD1963_ENTER_PARTIAL 0x12
#define SSD1963_ENTER_NORMAL 0x13
#define SSD1963_EXIT_INVERT 0x20
#define SSD1963_ENTER_INVERT 0x21
#define SSD1963_SET_GAMMA 0x26
#define SSD1963_BLANK_OFF 0x28
#define SSD1963_BLANK_ON 0x29
#define SSD1963_CLEAR_WINDOW 0x2D
#define SSD1963_WRITE_MEMORY_START 0x2C
#define SSD1963_READ_MEMORY 0x2E
#define SSD1963_SET_PARTIAL_AREA 0x30
#define SSD1963_SET_SCROLL_AREA 0x33
#define SSD1963_SET_TEAR_OFF 0x34
#define SSD1963_SET_TEAR_ON 0x35
#define SSD1963_MEM_ACCESS_CTRL 0x36
#define SSD1963_VERTICAL_SCROLL 0x37
#define SSD1963_IDLE_OFF 0x38
#define SSD1963_IDLE_ON 0x39
#define SSD1963_SET_PIX_FORMAT 0x3A
#define SSD1963_SET_IMAGE_FUNC 0x3B
#define SSD1963_WRITE_MEMORY_CONTINUE 0x3C
#define SSD1963_READ_MEMORY_CONTINUE 0x3E
#define SSD1963_SET_COLUMN 0x2A
#define SSD1963_SET_ROW 0x2B
#define SSD1963_SET_XY 0x2C
#define SSD1963_SET_TE_LINE 0x40
#define SSD1963_GET_SCAN_LINE 0x45
#define SSD1963_GET_HOR_PERIOD 0x44
#define SSD1963_SET_PLL_MN 0xE0
#define SSD1963_SET_PLL 0xE2
#define SSD1963_SET_PLL_ENABLE 0xE3
#define SSD1963_SET_DESKTOP_START 0xEA
// ==================== 基础操作函数 ====================
/**
* @brief 写入命令
* @param cmd 命令字节
*/
static void ssd1963_write_cmd(uint8_t cmd)
{
SSD1963_CMD_ADDR = cmd;
}
/**
* @brief 写入数据字节
* @param data 数据字节
*/
static void ssd1963_write_data(uint8_t data)
{
SSD1963_DATA_ADDR = data;
}
/**
* @brief 写入 16 位数据
* @param data 16 位数据
*/
static void ssd1963_write_data_16(uint16_t data)
{
SSD1963_DATA_ADDR = data;
}
/**
* @brief 写入 32 位数据(分 4 次)
* @param data 32 位数据
*/
static void ssd1963_write_data_long(uint32_t data)
{
ssd1963_write_data((data >> 24) & 0xFF);
ssd1963_write_data((data >> 16) & 0xFF);
ssd1963_write_data((data >> 8) & 0xFF);
ssd1963_write_data(data & 0xFF);
}
// ==================== 显示设置函数 ====================
/**
* @brief 设置显示窗口(GRAM 区域)
* @param x1 起始 X 坐标
* @param y1 起始 Y 坐标
* @param x2 结束 X 坐标
* @param y2 结束 Y 坐标
*/
void ssd1963_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
ssd1963_write_cmd(SSD1963_SET_COLUMN);
ssd1963_write_data_long(x1);
ssd1963_write_data_long(x2);
ssd1963_write_cmd(SSD1963_SET_ROW);
ssd1963_write_data_long(y1);
ssd1963_write_data_long(y2);
ssd1963_write_cmd(SSD1963_WRITE_MEMORY_START); // 准备写 GRAM
}
/**
* @brief 清屏
* @param color 填充颜色 (RGB565)
*/
void ssd1963_clear(rt_uint16_t color)
{
uint32_t i;
uint32_t total_pixels = 480 * 272; // 根据实际分辨率调整
ssd1963_set_window(0, 0, 479, 271);
for (i = 0; i < total_pixels; i++)
{
SSD1963_DATA_ADDR = color;
}
}
// ==================== 初始化函数 ====================
/**
* @brief 初始化 SSD1963 控制器
* 支持 480x272 分辨率,16位色
*/
void ssd1963_init(void)
{
rt_pin_mode(LCD_RST_PIN, PIN_MODE_OUTPUT);
// 复位
rt_pin_write(LCD_RST_PIN, PIN_LOW);
rt_thread_mdelay(100);
rt_pin_write(LCD_RST_PIN, PIN_HIGH);
rt_thread_mdelay(150);
// 软件复位
ssd1963_write_cmd(SSD1963_SOFT_RESET);
rt_thread_mdelay(10);
// ============= 设置 PLL =============
// PLL = (CLK * (M+1)) / (N+1), 典型主频 10MHz 输入
ssd1963_write_cmd(SSD1963_SET_PLL_MN);
ssd1963_write_data(0x23); // M = 35, M+1=36
ssd1963_write_data(0x02); // N = 2, N+1=3
ssd1963_write_data(0x04); // DIV = 4
// 启用 PLL
ssd1963_write_cmd(SSD1963_SET_PLL_ENABLE);
ssd1963_write_data(0x01); // 开启 PLL
rt_thread_mdelay(1);
ssd1963_write_cmd(SSD1963_SET_PLL_ENABLE);
ssd1963_write_data(0x03); // 锁定 PLL
rt_thread_mdelay(5);
// 选择 PLL 作为系统时钟
ssd1963_write_cmd(SSD1963_SET_PLL);
ssd1963_write_data(0x03);
// ============= 设置 LCD 模式 =============
ssd1963_write_cmd(0xB0); // Set LCD Mode
ssd1963_write_data(0x20); // 24-bit/pixel, TFT 模式
ssd1963_write_data(0x01); // HSYNC+VSYNC 控制
ssd1963_write_data_long(480); // LCD 宽度
ssd1963_write_data_long(272); // LCD 高度
ssd1963_write_data_long(41); // HSYNC 脉冲宽度 (41)
ssd1963_write_data_long(2); // HSYNC 起始延迟 (HBP)
ssd1963_write_data_long(2); // HSYNC 结束延迟 (HFP)
ssd1963_write_data_long(10); // VSYNC 脉冲宽度 (10)
ssd1963_write_data_long(2); // VSYNC 起始延迟 (VBP)
ssd1963_write_data_long(2); // VSYNC 结束延迟 (VFP)
// ============= 设置像素格式 =============
ssd1963_write_cmd(SSD1963_SET_PIX_FORMAT);
ssd1963_write_data(0x55); // 16位色 (RGB565)
// ============= 设置内存访问方向 =============
ssd1963_write_cmd(SSD1963_MEM_ACCESS_CTRL);
ssd1963_write_data(0x08); // RGB, 正常方向
// ============= 设置背光 =============
// rt_pin_mode(LCD_BL_PIN, PIN_MODE_OUTPUT);
// rt_pwm_enable(LCD_BL_PIN);
// rt_pwm_set(LCD_BL_PIN, 1000, 50000); // 1kHz, 50% 占空比 (可调)
// rt_pin_write(LCD_BL_PIN, PIN_HIGH); // 直接输出高电平点亮
// ============= 开启显示 =============
ssd1963_write_cmd(SSD1963_EXIT_SLEEP);
rt_thread_mdelay(10);
ssd1963_write_cmd(SSD1963_BLANK_OFF);
ssd1963_write_cmd(SSD1963_ENTER_NORMAL);
rt_thread_mdelay(10);
ssd1963_write_cmd(SSD1963_IDLE_OFF);
// 初始窗口
ssd1963_set_window(0, 0, 799, 479);
// 可选:清屏为黑色
ssd1963_clear(0x00f0);
}
// ==================== LVGL 对接接口 (可选封装) ====================
/**
* @brief 获取屏幕宽度
* @return 宽度
*/
rt_uint16_t ssd1963_get_width(void)
{
return 800;
}
/**
* @brief 获取屏幕高度
* @return 高度
*/
rt_uint16_t ssd1963_get_height(void)
{
return 480;
}
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-10-26 Administrator the first version
*/
#ifndef APPLICATIONS_SSD1963_H_
#define APPLICATIONS_SSD1963_H_
#include <rtthread.h>
// ==================== FSMC 地址映射(必须放在头文件中供外部使用)====================
// 假设使用 FSMC Bank1, NE1, A16 作为 RS/DC 控制线
#define SSD1963_BASE_ADDR ((uint32_t)(0x60000000)) // FSMC_NE1
#define LCD_CMD_ADDR (LCD_BASE_ADDR + 0x00000000) // A0 = 0
#define LCD_DATA_ADDR (LCD_BASE_ADDR + 0x00020000) // A0 = 1
// 定义 FSMC 地址:假设使用 Bank1, Base Address 0x60000000,A0 对应地址位1
#define SSD1963_CMD_ADDR *(volatile uint16_t *)(0x60000000)
#define SSD1963_DATA_ADDR *(volatile uint16_t *)(0x60020000)
#define LCD_Write_Cmd(cmd) (*(__IO uint16_t*)LCD_CMD_ADDR = (cmd))
#define LCD_Write_Data(dat) (*(__IO uint16_t*)LCD_DATA_ADDR = (dat))
// 函数声明
void ssd1963_init(void);
void ssd1963_set_window(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void ssd1963_clear(rt_uint16_t color);
rt_uint16_t ssd1963_get_width(void);
rt_uint16_t ssd1963_get_height(void);
#endif /* APPLICATIONS_SSD1963_H_ */
+4 -3
View File
@@ -16,6 +16,7 @@
#include "RUN_LED.h"
#include "DB_SQLite.h"
#include "DATA_comm.h"
#include "DATA_uart.h"
#include "uart_rs485.h"
#define DBG_TAG "main"
@@ -26,11 +27,11 @@ extern rt_sem_t mount_sem; // 引用上面SD挂载线程定义的信号量
int main(void)
{
rt_sem_take(mount_sem, rt_tick_from_millisecond(5000)); // 等待挂载完成,最多等待 5 秒
thread_RUN_LED();//运行指示灯线程
thread_DB_SQLite();
rt_thread_mdelay(1000);
data_comm_init();
app_uart_rs485_startup();
start_uart_thread();
thread_RUN_LED();//运行指示灯线程
return RT_EOK;
}
+1 -1
View File
@@ -72,7 +72,7 @@ int stm32_sdcard_mount(void)
tid = rt_thread_create("sd_mount",
sd_mount,
RT_NULL,
4096, // 建议增大栈,避免溢出
1024*4, // 建议增大栈,避免溢出
RT_THREAD_PRIORITY_MAX - 2,
20);
if (tid != RT_NULL)