当前位置: 首页 > news >正文

Window C++模拟单片机控制TFT屏幕和SD卡

因为每次都要做大量的测试,上传到单片机实在是太费事,所以写了这个模拟项目用来测试
很多方法我没有补充进去,因为太多了,如果有需要请自行补充

stdafx.h

#pragma once

#include<iostream>
#include<atlimage.h>
#include<time.h>
#include<string>
#include <ws2tcpip.h>
#include<Windows.h>

FS.h

#pragma once
#include"stdafx.h"
#define HSPI 0
#define OUTPUT 0
#define HIGH 0
#define LOW 0
class SPIClass
{
public:
	SPIClass(int t) {};
	void begin(int, int, int, int) {};
};
class serial {
public:
	serial() {};
	void begin(int) {};
	void println(const char *t) {
		printf("%s\n", t);
	};
};
void pinMode(int, int);
void digitalWrite(int, int);

SD.h

#pragma once
#include"stdafx.h"
#define CARD_NONE 0
#pragma warning(disable:4996)
#define MN_PATH "D:\\Program Files\\all\\desktop\\SD"
class String :public std::string
{
public:
	String() : std::string() {}
	String(const char*t) :std::string(t) {}
	int indexOf(const char *st)
	{
		return this->find(st, 0);
	}
	String substring(int _off, int ct = -1)
	{
		if (ct == -1)
		{
			ct = this->length();
		}
		String h= this->substr(_off, ct).c_str();
		return h;
	}
};
class File
{
private:
	FILE* fp;
public:
	File(const char *path)
	{
		this->fp = fopen(path, "rb");
	}
	explicit operator bool() const {  // 防止隐式转换到其他类型
		return fp!=NULL; /* 根据对象状态返回true/false */;
	}
	String readStringUntil(char ends)
	{
		String t = "";
		char t1;
		int lna = 0;
		while ((lna = fread(&t1, 1, 1, this->fp))>0)
		{
			t+=t1;
			if (t1 == ends)
				break;
		}
		return t;
	}
	void close()
	{
		fclose(this->fp);
	}
	void seek(long pos)
	{
		fseek(this->fp, pos, 0);
	}
	int read(void *addr, int size)
	{
		return fread(addr, size, 1, this->fp);
	}
};
class sd {
public:
	sd() {};
	bool begin(int, SPIClass&t) { return true; }
	int cardType() { return 1; }
	File open(const char*path)
	{
		int len = strlen(path) + 1;
		char *t = new char[len];
		memset(t, 0, sizeof(len));
		strcat(t,path);
		for (int i = 0; i < len; i++)
			if (t[i] == '/')
				t[i] = '\\';
		std::string p = MN_PATH;
		p += t;
		File file(p.c_str());
		return file;
	}
};

SPI.h

#pragma once
#include"stdafx.h"
void delay(int min);
long millis();
void loop();
void setup();
void setmillis(long t);

TFT_eSPI.h

#pragma once
#include"stdafx.h"
#pragma warning(disable:4996)
#define TFT_BLUE 0x1F
#define TFT_GREEN 0x3E0
#define TFT_BLACK 0x0000
#define TFT_WHITE 0x7FFF
#define TFT_WIDTH 160
#define TFT_HEIGHT 128
#define TFT_SCA 4

LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
DWORD WINAPI CTF(void*E);
int Get_real_col(uint16_t c1);
class TMp2
{
public:
	HWND*hwnd;
	HINSTANCE *hInstance;
	bool *ok;
};
class TFT_eSPI
{
public:
	static HINSTANCE hInstance;
	static HWND hwnd;
	static bool ok,canrun;
	static void setH(HINSTANCE hInstance)
	{
		TFT_eSPI::hInstance = hInstance;
	}
	static CImage img;
	static bool img_ch;
	static void CT()
	{
		if (ok)return;
		TMp2 *t=new TMp2();
		t->hwnd = &(TFT_eSPI::hwnd);
		t->hInstance = &(TFT_eSPI::hInstance);
		t->ok = &(TFT_eSPI::ok);
		CreateThread(0, 0, CTF, t, 0, 0);
	}
	int col;
	TFT_eSPI() {

	}
	void init()
	{
		CT();
		Sleep(400);
		while (!ok)
		{
			Sleep(400);
		}
		img.Create(TFT_WIDTH, TFT_HEIGHT, 24);
	}
	void setRotation(int) {};
	void fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
	{
		HDC hdc = GetDC(hwnd);
		RECT rect;
		rect.left = x* TFT_SCA;
		rect.top = y * TFT_SCA;
		rect.right = x * TFT_SCA +(w * TFT_SCA);
		rect.bottom = y * TFT_SCA +(h * TFT_SCA);
		HBRUSH hb = CreateSolidBrush(Get_real_col(color));
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hb);
		FillRect(hdc, &rect, hb);
		SelectObject(hdc, hOldBrush);
		DeleteObject(hb);
		ReleaseDC(hwnd, hdc);
	}
	void fillCircle(int prevX1, int prevY1, int R, int BG_COLOR)
	{
		int prevX = prevX1 * TFT_SCA;
		int prevY = prevY1 * TFT_SCA;
		HDC hdc = GetDC(hwnd);
		HPEN hTransparentPen = CreatePen(PS_NULL, 1, RGB(0, 0, 0));
		HPEN hOldPen = (HPEN)SelectObject(hdc, hTransparentPen);
		// 设置画笔颜色和样式
		HBRUSH hb = CreateSolidBrush( Get_real_col(BG_COLOR));
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hb);

		// 绘制圆,左上角坐标(100, 100),半径100
		int r = R *TFT_SCA;
		Ellipse(hdc, prevX-r, prevY-r, prevX+r, prevY+r);

		// 恢复原来的画笔并删除新画笔
		SelectObject(hdc, hOldPen);
		SelectObject(hdc, hOldBrush);
		DeleteObject(hTransparentPen);
		DeleteObject(hb);
		ReleaseDC(hwnd, hdc);
	}
	void fillScreen(uint16_t col)
	{
		RECT rect;
		rect.left = 0;
		rect.top = 0;
		rect.right = TFT_WIDTH* TFT_SCA;
		rect.bottom = TFT_HEIGHT* TFT_SCA;
	 	HBRUSH hb= CreateSolidBrush(Get_real_col(col));
		HDC hdc = GetDC(hwnd);
		FillRect(hdc, &rect, hb);
		ReleaseDC(hwnd,hdc);
		DeleteObject(hb);
	}
	void setTextColor(uint16_t col)
	{
		this->col = Get_real_col(col);
	}
	void drawString(const char *str, int x, int y, int fontsize=1)
	{
		RECT rect;
		rect.left = x* TFT_SCA;
		rect.top = y* TFT_SCA;
		rect.right = TFT_WIDTH * TFT_SCA;
		rect.bottom = TFT_HEIGHT * TFT_SCA;
		HDC hdc = GetDC(hwnd);
		SetTextColor(hdc, this->col);
		LOGFONT lf;
		memset(&lf, 0, sizeof(LOGFONT));
		lf.lfHeight = -MulDiv(fontsize* TFT_SCA *5, GetDeviceCaps(hdc, LOGPIXELSY), 72); // 设置字体高度(20磅)
		lf.lfWeight = FW_NORMAL;  // 字体粗细
		strcpy(lf.lfFaceName, "Arial"); // 字体名称
		HFONT hFont = CreateFontIndirect(&lf);
		HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
		int nOldMode = SetBkMode(hdc, TRANSPARENT);
		DrawText(hdc, str, strlen(str), &rect, DT_LEFT); 
		SetBkMode(hdc, nOldMode);
		SelectObject(hdc, hOldFont);
		DeleteObject(hFont);
		ReleaseDC(hwnd, hdc);
	}
	void startWrite()
	{
		img_ch = true;
	}
	int x,y,w,h;
	void setAddrWindow(int x, int y, int w, int h)
	{
		this->h = h;
		this->x = x;
		this->y = y;
		this->w = w;
	}
	void pushPixels(uint16_t*rowBuffer, int size)
	{
		unsigned char* rgb1 = (unsigned char*)img.GetBits();
		int pitch1 = img.GetPitch();
		int i = this->y;
		for (int j1 = 0; j1 < size; j1 ++)
		{
			int j = this->x + j1;
			uint16_t c = rowBuffer[j1];
			c = (c << 8) | (c >> 8);
			c = c >> 1;
			unsigned char r, g, b;
			r = (c >> 10&0x1F) * 8;
			g = (c >> 5 & 0x1F) * 8;
			b = (c & 0x1F) * 8;
			*(rgb1 + (j * 3) + (i * pitch1) + 0) = b;
			*(rgb1 + (j * 3) + (i * pitch1) + 1) = g;
			*(rgb1 + (j * 3) + (i * pitch1) + 2) = r;
		}
	}
	void endWrite()
	{
		HDC hdc = GetDC(TFT_eSPI::hwnd);
		TFT_eSPI::img.StretchBlt(hdc, 0, 0, TFT_SCA*TFT_WIDTH, TFT_SCA * TFT_HEIGHT);
		ReleaseDC(hwnd, hdc);
	}
};
int constrain(int value, int min_value, int max_value);

WiFi.h

#pragma once
#include"stdafx.h" 
#pragma comment(lib, "ws2_32.lib")
#define WL_CONNECTED 0
class Tmp
{
public:
	Tmp()
	{

	}
	const char* toString()
	{
		return "192.168.0.123";
	}
};
class wifi
{
public:
	static __time64_t _time_net;
	wifi() {
		WSADATA wsaData;
		WSAStartup(MAKEWORD(2, 2), &wsaData);
	};
	void begin(const char*, const char*) { Sleep(1000); }
	int status()
	{
		return 0;
	}
	Tmp localIP()
	{
		Tmp t;
		return t;
	}
};
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* ntpServer);
bool getLocalTime(tm* tm1);

other.cpp

#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include "TFT_eSPI.h"
#include "WiFi.h"
void delay(int min)
{

}
long t1 = 0;
void setmillis(long t)
{
	t1 = t;
}
long millis()
{
	return t1;
}
void digitalWrite(int, int) {}
void pinMode(int, int)
{

}
__time64_t wifi::_time_net = 0;

uint64_t tryNtpServer(const char* server) {
	SOCKET sock = INVALID_SOCKET;
	char buffer[48] = { 0 };
	struct addrinfo hints = { 0 }, * res = nullptr;

	// 解析DNS
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_DGRAM;
	if (getaddrinfo(server, "123", &hints, &res) != 0) {
		std::cerr << "[DNS Error] " << server << std::endl;
		return 0;
	}

	// 遍历所有解析到的IP地址
	for (auto* ptr = res; ptr != nullptr; ptr = ptr->ai_next) {
		sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
		if (sock == INVALID_SOCKET) continue;

		// 配置套接字选项
	   // setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&NTP_TIMEOUT, sizeof(NTP_TIMEOUT));

		// 构造NTP请求包
		memset(buffer, 0, 48);
		buffer[0] = 0x1B;  // NTPv3客户端模式

		// 发送请求
		if (sendto(sock, buffer, 48, 0,
			ptr->ai_addr, (int)ptr->ai_addrlen) <= 0) {
			closesocket(sock);
			continue;
		}

		// 接收响应
		int bytes = recv(sock, buffer, 48, 0);
		if (bytes > 0) {
			uint32_t seconds = ntohl(*((uint32_t*)(buffer + 40)));
			freeaddrinfo(res);
			closesocket(sock);
			return seconds - 2208988800ULL;  // 转换为Unix时间戳
		}
		closesocket(sock);
	}

	freeaddrinfo(res);
	return 0;
}
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* ntpServer)
{
	wifi::_time_net = tryNtpServer(ntpServer);
}
bool getLocalTime(tm* tm1)
{
	long long t = (wifi::_time_net +( t1/1000));
	tm* tm_t =localtime(&t);
	memcpy(tm1, tm_t, sizeof(tm));
	return true;
}
HINSTANCE TFT_eSPI::hInstance=NULL;
HWND TFT_eSPI::hwnd=NULL;
bool TFT_eSPI::ok=false;
bool TFT_eSPI::canrun = true;
bool TFT_eSPI::img_ch = false;
CImage TFT_eSPI::img;
LRESULT CALLBACK GLWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg)
	{
	case WM_CLOSE:
		PostQuitMessage(0);
		TFT_eSPI::canrun = false;
		return 0;
	default:
		break;
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}

DWORD WINAPI CTF(void*e)
{
	TMp2*E = (TMp2*)e;
	WNDCLASSEX wndclass;
	wndclass.cbClsExtra = 0;
	wndclass.cbSize = sizeof(WNDCLASSEX);
	wndclass.cbWndExtra = 0;
	wndclass.hbrBackground = NULL;
	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndclass.hIcon = NULL;
	wndclass.hIconSm = NULL;
	wndclass.hInstance = *(E->hInstance);
	wndclass.lpfnWndProc = GLWindowProc;
	wndclass.lpszClassName = "GLWindow";
	wndclass.lpszMenuName = NULL;
	wndclass.style = CS_VREDRAW | CS_HREDRAW;
	ATOM atom = RegisterClassEx(&wndclass);
	if (!atom)
	{
		MessageBox(NULL, "Notice", "Error", MB_OK);
		return 0;
	}
	HWND hwnd = CreateWindowEx(NULL, "GLWindow", "TFT模拟", WS_OVERLAPPEDWINDOW, 0, 0, TFT_WIDTH*TFT_SCA+16, TFT_HEIGHT * TFT_SCA+37, NULL, NULL, *(E->hInstance), NULL);
	*(E->hwnd) = hwnd;
	ShowWindow(hwnd, SW_SHOW);
	UpdateWindow(hwnd);
	*(E->ok) = true;
	//程序持续运行
	MSG msg;
	while (true)
	{
		if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
		{
			if (msg.message == WM_QUIT)
				break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return 0;
}
int Get_real_col(uint16_t c)
{
	unsigned char r, g, b;
	r = (c >> 10 & 0x1F) * 8;
	g = (c >> 5 & 0x1F) * 8;
	b =( c & 0x1F )* 8;
	//printf("%d %d %d %d\n",c, r,g,b);
	return RGB(r,g,b);
}
int constrain(int value, int min_value, int max_value) {
	return min(max(value, min_value), max_value);
}

#ifdef _CONSOLE
int main()
#elif
int WINAPI WinMain(HINSTANCE h1, HINSTANCE h2, LPSTR cmd, int show)
#endif
{
#ifdef _CONSOLE
	HINSTANCE h1 = GetModuleHandle(NULL);
#endif
	TFT_eSPI::setH(h1);
	setup();
	long t = 0;
	while (1)
	{
		if (!TFT_eSPI::canrun)
			break;
		loop();
		/*if (TFT_eSPI::img_ch)
		{
			TFT_eSPI::img_ch = false;
		}*/
		Sleep(50);
		t = t + 50;
		setmillis(t);
	}
}

测试用.cpp

#include "SPI.h"
#include "wifi.h"
#include "FS.h"
#include "SD.h"
#include "TFT_eSPI.h"
#ifdef WIN32
serial Serial;
wifi WiFi;
sd SD;
#endif

const char* ntpServer = "time.windows.com";
const long gmtOffset_sec = 8 * 3600; // 东八区(北京时间)
const int daylightOffset_sec = 0;
#define HSPI_CLK 14
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_CS 15
#define SD_CS 15
#define TFT_CS 5 // TFT片选引脚
TFT_eSPI tft;
SPIClass spiSD(HSPI); // 创建HSPI对象
void setup() {
    tft.init();
    tft.setTextColor(TFT_WHITE);
    tft.fillScreen(TFT_BLACK);
    tft.fillRect(60-5, 20, 9, 32, TFT_GREEN);
    tft.fillRect(100-5, 20, 9, 32, TFT_GREEN);
}
unsigned long lastTime = 0;
int y = 0;
#define AD 8
int ad = AD;
int t11 = 3;
void loop() {
    if (t11 >= 3|| t11==2)
    {
        tft.fillRect(60 - 5, 20 + y, 9, AD, TFT_BLACK);
    }
    if (t11 >= 3 || t11 == 1)
    {
        tft.fillRect(100 - 5, 20 + y, 9, AD, TFT_BLACK);
    }
    y += ad;
    if (t11 >= 3 || t11 == 2)
    {
        tft.fillRect(60 - 5, 20 + y, 9, 32 - y, TFT_GREEN);
    }
    if (t11 >= 3 || t11 == 1)
    {
        tft.fillRect(100 - 5, 20 + y, 9, 32 - y, TFT_GREEN);
    }
    if (y <= 0) {
        ad = AD;
        Sleep(rand() % 10*500);
        t11 = rand() % 3 + 1;
    }
    else if (y >= 32)
    {
        ad = -AD;
    }
}

相关文章:

  • etcd心跳机制与存储性能影响深度分析
  • 三元组排序(acwing)c++
  • 26、IO流(只是小入门)
  • netty如何处理粘包半包
  • 股市能量场理论Python实战指南
  • ubuntu Linux 正确设置中文环境的方法
  • 计算机基础:二进制基础03,二进制数的位基和位权
  • 基于SpringBoot和PostGIS的省域“地理难抵点(最纵深处)”检索及可视化实践
  • 开篇词 | Go 项目开发极速入门课介绍
  • Redis学习笔记系列(一)——Redis简介及安装
  • 上手大模型应用LangChain
  • Android平台GB28181设备接入模块之SmartGBD
  • pandas 数据透视表
  • Win10环境借助DockerDesktop部署单节点Redis6
  • SwiftUI之状态管理全解析
  • tcc编译器教程1 配置tcc编译器环境
  • Python面向对象编程入门:从类与对象到方法与属性
  • Deepseek 模型蒸馏
  • Kotlin语言特性(一):空安全、扩展函数与协程
  • 【华三】SR-MPLS TE 静态配置实验
  • 商品网站怎么做/百度推广需要多少钱
  • 深圳企业网站建设专业/万网官网域名注册
  • 天津建设工程评标专家网站/今天新闻头条新闻
  • 正规的南昌网站建设/网络营销渠道有哪几种
  • 一站式做网站开发/网络推广运营是做什么
  • 嘉兴建设工程造价信息网站/网络营销技术