CH343PT库使用<三> GPIO设置


前言

我们在使用USB转串口设备时候不仅会使用串口通讯功能,有时候还会用到芯片的GPIO功能,如设置GPIO输入、输出功能。支持GPIO设置的芯片型号有CH9101、CH9102、CH9103、CH9104、CH347、CH344、CH348等型号。下面将介绍如何使用CH343PT库中函数去配置上述芯片的GPIO输入、输出功能。


一、配置GPIO功能函数简介

有两套设置GPIO函数,设置CH9101、CH9102、CH9103、CH344和CH347使用CH910x_XX函数,设置CH348使用CH348_XX函数。

1.1 配置GPIO函数(适应CH910X、CH344、CH347)

①配置GPIO的功能和I/O方向

UCHAR	WINAPI	CH910x_GpioConfig(
			HANDLE			iPortH,    
			ChipPropertyS*  iChipProperty,
			ULONG			iEnable,        
			ULONG			iFuncSet,       
			ULONG			iSetDirOut);    

参数IPortH为串口句柄值;
参数iChipProperty芯片属性信息,具体介绍可参考我的文章;
参数iEnable为位使能:以位对应引脚号,位0对应GPIO0,位1对应GPIO1;某位为1,表示iGpioFunc,iSetDirOut对应位有效
参数iFuncSet为功能设置:某位值为0,表示对应引脚为芯片默认功能使用;为1,表示对应引脚作为GPIO功能使用;
参数iSetDirOut为GPIO脚方向设置:某位为0表示对应引脚方向为输入;某位为1表示对应引脚方向为输出。

②获取GPIO引脚配置:引脚功能、方向、电平

UCHAR	WINAPI	CH910x_GetGpioConfig(
			HANDLE			iPortH, 
			ChipPropertyS   *iChipProperty, 
			PULONG			FuncSet,        
			PULONG			SetDirOut,      
			PULONG       SetDataOut);  

参数IPortH为串口句柄值;
参数iChipProperty芯片属性信息,可为NULL,具体介绍可参考我的文章;
参数FuncSet为功能设置:某位值为0,表示对应引脚为芯片默认功能使用;为1,表示对应引脚作为GPIO功能使用;
参数SetDirOut为GPIO脚方向设置:某位为0表示对应引脚方向为输入;某位为1表示对应引脚方向为输出;
参数SetDataOut为GPIO脚电平值:1表示高电平;0表示低电平。

③设置GPIO引脚电平状态
使用该函数可以设置GPIO引脚为输出高电平或输出低电平功能。

UCHAR	WINAPI	CH910x_GpioSet(  
			HANDLE			iPortH,       
			ChipPropertyS*  iChipProperty,
			ULONG			iEnable,        
			ULONG			iSetDataOut );

参数IPortH为串口句柄值;
参数iChipProperty芯片属性信息;
参数iEnable为数据有效标志,位序号与GPIOx的序号对应,位值为1表示iSetDataOut的对应位数据有效,为0表示数据无效;
参数iSetDataOut IO输出数据,如果GPIO方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平

④读取GPIO引脚电平状态

UCHAR	WINAPI	CH910x_GpioGet(   
			HANDLE			iPortH,    
			ChipPropertyS*   iChipProperty,
			PULONG			iStatus );   

参数iPortH为串口句柄值;
参数iChipProperty芯片属性信息;
参数iStatus为引脚状态,其GPIOx序号对应数据位号。如GPIO1,对应iStatus值中的bit1,可用CH910x_GPIO_xx位掩码取值。

1.2 配置GPIO函数(适应CH348)

①获取GPIO配置:功能和I/O方向,输出脚默认值

UCHAR	WINAPI	CH348_GetGpioConfig(
			HANDLE		    	iPortH,         // 串口句柄值
			ChipPropertyS       *ChipProperty,  // 芯片属性值
			ULONGLONG			*FuncSet,       // 功能设置:某位值为0,表示对应引脚为芯片默认功能使用;为1,表示对应引脚作为GPIO功能使用;
			ULONGLONG			*SetDirOut,     // GPIO脚方向设置:某位为0表示对应引脚方向为输入;某位为1表示对应引脚方向为输出	
			ULONGLONG           *SetDataOut);   // IO输出数据,如果GPIO方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平

②配置GPIO的功能和I/O方向

//iEnable,iFuncSet,iSetDirOut为64位变量,位序号与GPIO引脚号对应。
//建议使用前先调用CH348_GetGpioConfig获取iFuncSet,iSetDirOut初值后再进行设置
UCHAR	WINAPI	CH348_GpioConfig(
			HANDLE		    	iPortH,         // 串口句柄值
			ChipPropertyS*      iChipProperty,  // 芯片属性值
			ULONGLONG			iEnable,        // 位使能:以位对应引脚号,位0对应GPIO0,位1对应GPIO1;某位为1,表示iGpioFunc,iSetDirOut对应位有效											 
			ULONGLONG			iFuncSet,       // 功能设置:某位值为0,表示对应引脚为芯片默认功能使用;为1,表示对应引脚作为GPIO功能使用;
			ULONGLONG			iSetDirOut,     // GPIO脚方向设置:某位为0表示对应引脚方向为输入;某位为1表示对应引脚方向为输出	
			ULONGLONG           iSetDataOut);    // IO输出数据,如果GPIO方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平

③设置某个GPIO引脚电平状态,相应引脚需开启GPIO功能

UCHAR	WINAPI	CH348_GpioSet(  
			HANDLE			iPortH,         // 串口句柄值
			ChipPropertyS*   iChipProperty,  // 芯片属性值
			UCHAR	        iGpioIndex,     // GPIO脚序号,0-63
			UCHAR		    iGpioLevel );   // GPIO电平,1为高电平;1:低电平

④设置多个GPIO引脚电平状态,相应引脚需开启GPIO功能

UCHAR	WINAPI	CH348_GpioMSet(  
			HANDLE			iPortH,          // 串口句柄值
			ChipPropertyS*   iChipProperty,   // 芯片属性值
			ULONGLONG        iGpioMIndex,     // GPIO序号掩码,位0-63
			ULONGLONG		iGpioMLevel);     // GPIO电平掩码,与上iGpioMIndex位置对应。1:高电平,0:低电平

⑤获取某个GPIO引脚电平状态,相应引脚需开启GPIO功能

UCHAR	WINAPI	CH348_GpioGet(  
			HANDLE			iPortH,         // 串口句柄值
			ChipPropertyS*   iChipProperty,  // 芯片属性值
			UCHAR	        iGpioIndex,     // GPIO脚序号 0-63
			PUCHAR		    GpioLevel );     // GPIO电平,1为高电平;1:低电平

二、GPIO配置Demo

2.1 使用CH910x_XX函数配置GPIO

配置USB转串口设备的GPIO步骤如下:
①打开串口;
②调用CH343PT_GetChipProperty函数获取芯片功能信息,如芯片型号,芯片型号字符串,芯片可配置的GPIO数量等信息(具体可以参考该篇文章);
③读GPIO默认配置,使用函数CH910x_GetGpioConfig;
④GPIO功能和IO方向配置(IO方向分为输入和输出),使用函数CH910x_GpioConfig;
⑤设置电平状态(高电平和低电平),使用函数CH910x_GpioSet,IO方向为输出时使用该函数;
⑥获取GPIO引脚电平状态,使用函数CH910x_GpioGet;
⑦关闭串口。

2.2 使用CH348_XX函数配置GPIO

配置USB转串口设备的GPIO步骤如下:
①打开串口;
②调用CH343PT_GetChipProperty函数获取芯片功能信息,如芯片型号,芯片型号字符串,芯片可配置的GPIO数量等信息;
③读GPIO默认配置,使用函数CH348_GetGpioConfig;
④GPIO功能和IO方向配置(IO方向分为输入和输出),使用函数CH348_GpioConfig;
⑤设置电平状态(高电平和低电平),使用函数CH348_GpioSet(设置某个GPIO电平状态)或者CH348_GpioMSet(设置多个引脚GPIO状态),IO方向为输出时使用该函数;
⑥获取GPIO引脚电平状态,使用函数CH348_GpioGet或者CH348_GpioMGet;
⑦关闭串口。


三、软件实现

使用VC6++新建一个对话框,界面如下。
在这里插入图片描述

⑴插入CH9102F,打开串口,界面如下:
在这里插入图片描述
从图中可知,芯片型号为CH9102F,共有5个GPIO。

⑵选择配置GPIO3引脚为输出功能,设置引脚为低电平(界面设置:需勾选引脚功能、IO方向、IO状态取消勾选),然后点击配置芯片GPIO按钮,设置成功后再点击设置GPIO电平按钮,设置成功后可以用万用表量一下GPIO3是否为地电平(TTL电平),如果为低电平则设置成功,否则设置失败。
在这里插入图片描述
如果设置GPIO电平位高电平,勾选IO状态复选框,重复上述步骤即可。

⑶设置GPIO3为输入功能,勾选默认功能和IO状态复选框,IO方向复选框取消勾选。接下来点击配置芯片GPIO按钮,设置成功后点击获取GPIO电平按钮,获取GPIO3引脚电平状态。如果GPIO引脚接地,点击获取GPIO电平按钮,此时IO状态复选框被取消勾选。同理GPIO电平是高电平,点击获取GPIO电平按钮,IO状态复选框会被勾选上。
在这里插入图片描述

⑷需注意CH9102X和CH9101U型号的GPIO设置,CH9101U没有GPIO5需过滤,CH9102X没有GPIO4需过滤。插入CH9102X界面如下:
在这里插入图片描述
从图上可以看到CH9102X没有GPIO4共6个GPIO,需要使用结构体ChipPropertyS去判断打开的设备是否为CH9102X或者是CH910U,然后过滤相应的GPIO,以免设置错误。

⑸设置CH348的GPIO输出和输入功能,也是用上述同样的方法去设置。
在这里插入图片描述

四、代码实现

//main.cpp
#include "stdafx.h"
#include "resource.h"
#include <stdio.h>
#include <string>
#include "CH343PT.H"
#pragma comment (lib,"CH343PT")

HWND AfxMainHwnd; //主窗体句柄
ChipPropertyS ChipPro = {0};
HANDLE hCom; //串口句柄
UCHAR ChipType;
UCHAR TempGpioCount; //储存GPIO数
ULONG GpioEnable,GpioDir,GpioSta; //CH910x
ULONGLONG CH348FuncSet=0,CH348SetDirOut=0,CH348SetDataOut=0;

//获取串口友好名称friendlyName
VOID GetComFriendlyName()
{
	INT     wImageIdx = 0;
	SHORT   wItem = 0;
	CHAR    szBuf[MAX_PATH] = { 0 };
	TCHAR   szComName[MAX_PATH] = { 0 };
	
	SendDlgItemMessage(AfxMainHwnd,IDC_Com,CB_RESETCONTENT,0,0); //清除组合框列表
	HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, NULL, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES); //构建系统存在的所有设备列表
	if (hDevInfo == INVALID_HANDLE_VALUE)
	{
		return;
	};
	 
	SP_DEVINFO_DATA SpDevInfoData = { 0 };
	SpDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (DWORD i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &SpDevInfoData); i++)	
	{
			
		if (!SetupDiGetDeviceRegistryProperty(hDevInfo, &SpDevInfoData, SPDRP_CLASS, NULL, (PBYTE)szBuf, sizeof(szBuf), 0))
		{
			continue;
		}
		else
		{
			if (strcmp(szBuf, "Ports") != 0) //过滤端口,只取COM
			{
				continue;
			}
		}
		
		if (SetupDiGetDeviceRegistryProperty(hDevInfo, &SpDevInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)szComName, sizeof(szComName), 0))
		{
			ComCounts++;
			SendDlgItemMessage(AfxMainHwnd,IDC_AllCom,CB_ADDSTRING,0,(LPARAM)szComName); //向组合框中添加获取的设备友好名称
		}
	}
	SendDlgItemMessage(AfxMainHwnd,IDC_AllCom,CB_SETCURSEL,0,0); 
	if(hDevInfo)
		SetupDiDestroyDeviceInfoList(hDevInfo); //释放资源
}
//打开串口
BOOL OpenCom()
{
	CHAR TempBuf[64] = {0};
	INT i,BegainSer,EndSer,Len;
	std::string strTemp,strComName;
	CHAR ComName[16] = "";
	CHAR tempBuf[256] = "";
	CHAR buf[256] = "";
	BOOL Retval;
	//提取设备友好名称中的COM号
	GetDlgItemText(AfxMainHwnd,IDC_Com,tempBuf,sizeof(tempBuf));
	Len =strlen(tempBuf);
	strTemp = tempBuf;
	BegainSer = strTemp.find('(');
	EndSer = strTemp.find(')');
	for(i=0; i<EndSer-BegainSer-1; i++)
	{
		ComName[i] = tempBuf[BegainSer+1+i];
	}
	strComName += "\\\\.\\";
	strComName += ComName;
	hCom = CreateFile((LPCTSTR)strComName.c_str(),GENERIC_READ|GENERIC_WRITE,
			0,NULL,OPEN_EXISTING,
			NULL,
			NULL);
	if(hCom == INVALID_HANDLE_VALUE)
	{
		DbgPrint("打开串口失败!");
		return FALSE;
	}
	ChipType = CH343PT_GetChipProperty(hCom,&ChipPro); //获取串口芯片信息
	Retval = (ChipType!=0xFF);
	if(!Retval)
	{	
		DbgPrint("芯片信息获取失败!");
		CloseHandle(hCom);
		hCom= INVALID_HANDLE_VALUE;
		return FALSE;
	}

	if((ChipPro.ChipType == USER_TYPE_CH9101U) || (ChipPro.ChipType == USER_TYPE_CH9102X)) 
		TempGpioCount = ChipPro.GpioCount + 1; //CH9101U没有GPIO5,CH9102X没有GPIO4,界面需禁用对应的GPIO选项
	else
		TempGpioCount = ChipPro.GpioCount;
	return TRUE;
}

//关闭串口
BOOL CloseCom()
{
	if (INVALID_HANDLE_VALUE != hCom)
	{
		CloseHandle(hCom);
		hCom = INVALID_HANDLE_VALUE;		
	}
	return TRUE;
}

//获取芯片属性信息
VOID GetChipInfo()
{
	CHAR ChipTypeInfo[512] = "";
	CHAR TempStr[64] = "";
	if(ChipType != 0xFF)
	{
		sprintf(ChipTypeInfo,"芯片型号: %s, 共有%d个GPIO可配置", ChipPro.ChipTypeStr, ChipPro.GpioCount);
		sprintf(TempStr,"%s GPIO(%d)设置",ChipPro.ChipTypeStr, ChipPro.GpioCount);
		SetDlgItemText(AfxMainHwnd,IDC_DevInfo,ChipTypeInfo);
		SetDlgItemText(AfxMainHwnd,1300,TempStr);
	}
}

//添加GPIO
VOID InsertGPIO()
{
	int i;
	CHAR tempBuf[64] = "";
	if(ChipPro.GpioCount)
	{
		for(i = 0; i < TempGpioCount; i++)
		{
			memset(tempBuf,0,sizeof(tempBuf));
			if(ChipPro.ChipType == USER_TYPE_CH9101U && i==5)
				continue;
			if(ChipPro.ChipType == USER_TYPE_CH9102X && i==4)
				continue;
			sprintf(tempBuf,"GPIO%d",i);
			SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_ADDSTRING,0, (LPARAM)tempBuf);
		}
	}
	SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_SETCURSEL,0,0);
}

//读GPIO配置值
BOOL CH910xReadGpioConfig()
{
	UCHAR RetVal;
	int GpioIndex;
	
	//获取GPIO配置,方向,电平大小
	RetVal = CH910x_GetGpioConfig(hCom,&ChipPro,&GpioEnable,&GpioDir,&GpioSta); 
	if( RetVal != CH910x_SUCCESS )
	{
		DbgPrint("CH910x_GetGpioConfig配置失败!");
		return FALSE;
	}
	DbgPrint("CH910x_GetGpioConfig配置成功!");

	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取GPIO下标
	if(ChipPro.ChipType == USER_TYPE_CH9101U && GpioIndex == 5) //CH9101U没有GPIO5需过滤
		GpioIndex += 1;
	if(ChipPro.ChipType == USER_TYPE_CH9102X && GpioIndex >= 4) //CH9102X没有GPIO4需过滤
		GpioIndex += 1;
	CheckDlgButton(AfxMainHwnd,IDC_EnableGpio,(GpioEnable & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);
	CheckDlgButton(AfxMainHwnd,IDC_GpioDir,(GpioDir & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);
	CheckDlgButton(AfxMainHwnd,IDC_GpioLevel,(GpioSta & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);
	return TRUE;
}

VOID CH348ReadGpioConfig()
{
	UCHAR RetVal = 0;
	int GpioIndex;

	RetVal = CH348_GetGpioConfig(hCom,&ChipPro,&CH348FuncSet,&CH348SetDirOut,&CH348SetDataOut);
	if(RetVal!=CH910x_SUCCESS)
	{
		DbgPrint("CH348_GetGpioConfig设置成功!");
		return;
	}
	DbgPrint("CH348_GetGpioConfig设置成功!");
	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0);
	CheckDlgButton(AfxMainHwnd,IDC_EnableGpio,(CH348FuncSet & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);
	CheckDlgButton(AfxMainHwnd,IDC_GpioDir,(CH348SetDirOut & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);
	CheckDlgButton(AfxMainHwnd,IDC_GpioLevel,(CH348SetDataOut & (1<<GpioIndex))?BST_CHECKED:BST_UNCHECKED);	
	return;
}

//GPIO功能和IO方向配置
BOOL CH910xGpioConfig()
{
	int GpioIndex;
	UCHAR RetVal = 0;
	ULONG tempGpioEnable = 0, tempGpioDir = 0, tempFuncSet = 0;
	
	if(INVALID_HANDLE_VALUE == hCom)
	{
		DbgPrint("配置前需打开串口");
		return FALSE;
	}
	//从界面获取GPIO设置
	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取将设置的GPIO引脚
	if(ChipPro.ChipType == USER_TYPE_CH9101U && GpioIndex == 5) //CH9101U没有GPIO5需过滤
		GpioIndex += 1;
	if(ChipPro.ChipType == USER_TYPE_CH9102X && GpioIndex >= 4) //CH9102X没有GPIO4需过滤
		GpioIndex += 1;
	tempGpioEnable = 1<<GpioIndex;
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_EnableGpio) == BST_CHECKED)
		tempFuncSet = GpioEnable | (1<<GpioIndex);
	else
		tempFuncSet = GpioEnable & (~(1<<GpioIndex));
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioDir) == BST_CHECKED)
		tempGpioDir = GpioDir | (1<<GpioIndex);
	else
		tempGpioDir = GpioDir & (~(1<<GpioIndex));

	//设置GPIO功能和方向
	RetVal = CH910x_GpioConfig(hCom,&ChipPro,tempGpioEnable,tempFuncSet,tempGpioDir);
	if(RetVal==CH910x_SUCCESS) //设置成功
	{
		GpioEnable = tempFuncSet; //保存状态
		GpioDir = tempGpioDir;
		DbgPrint("CH910x_GpioConfig功能和方向已设置成功");
	}
	else //设置失败
	{
		DbgPrint("CH910x_GpioConfig设置失败!");
		return FALSE;
	}
	return TRUE;
}

VOID CH348GpioConfig()
{
	ULONG GpioIndex;
	ULONG RetVal;	

	ULONGLONG iFuncSet = 0;       // 功能设置:某位值为0,表示对应引脚为芯片默认功能使用;为1,表示对应引脚作为GPIO功能使用;
	ULONGLONG iSetDirOut = 0;     // GPIO脚方向设置:某位为0表示对应引脚方向为输入;某位为1表示对应引脚方向为输出	
	ULONGLONG iSetDataOut = 0;    // IO输出数据,如果GPIO方向为输出,那么某位清0时对应引脚输出低电平,某位置1时对应引脚输出高电平
	ULONGLONG iEnable = 0;        // 位使能:以位对应引脚号,位0对应GPIO0,位1对应GPIO1;某位为1,表示iGpioFunc,iSetDirOut对应位有效	

	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取将设置的GPIO引脚
	iEnable |= (__int64)1<<GpioIndex;
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_EnableGpio) == BST_CHECKED) //GPIO使能
		iFuncSet = iEnable | (1<<GpioIndex);
	else
		iFuncSet = iEnable & (~(1<<GpioIndex));
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioDir) == BST_CHECKED) //获取GPIO输入输出方向
		iSetDirOut = iEnable | (1<<GpioIndex);
	else
		iSetDirOut = iEnable & (~(1<<GpioIndex));
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioLevel) == BST_CHECKED) //获取GPIO输出电平
		iSetDataOut = iEnable | (1<<GpioIndex);
	else
		iSetDataOut = iEnable & (~(1<<GpioIndex));
	RetVal = CH348_GpioConfig(hCom,&ChipPro,iEnable,iFuncSet,iSetDirOut,iSetDataOut);
	if(RetVal==CH910x_SUCCESS)//更新GPIO状态
	{
		DbgPrint("CH348_GpioConfig功能和方向已设置成功!");
		//SendDlgItemMessage(AfxWndHwnd,IDC_348ReadGPIOCfg,BM_CLICK,0,0);
	}
	else
		DbgPrint("CH348_GpioConfig功能和方向已设置失败!");
	return;
}

//设置GPIO电平
BOOL CH910xSetGpioLevel()
{
	int GpioIndex;
	ULONG iEnable = 0,iSetDataOut = 0;
	UCHAR RetVal;
	
	//从界面获取GPIO设置
	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取将设置的GPIO引脚
	if(ChipPro.ChipType == USER_TYPE_CH9101U && GpioIndex == 5) //CH9101U没有GPIO5需过滤
		GpioIndex += 1;
	if(ChipPro.ChipType == USER_TYPE_CH9102X && GpioIndex >= 4) //CH9102X没有GPIO4需过滤
		GpioIndex += 1;
	
	if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioDir) == BST_CHECKED)
	{//设置GPIO为输出功能 
		iEnable = 1<<GpioIndex;
		if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioLevel) == BST_CHECKED)
			iSetDataOut = GpioSta | (1<<GpioIndex);
		else
			iSetDataOut = GpioSta & (~(1<<GpioIndex));
	}
	//设置GPIO为输出功能的GPIO状态,1位高电平,0位低电平
	RetVal = CH910x_GpioSet(hCom,&ChipPro,iEnable,iSetDataOut);
	if(RetVal == CH910x_SUCCESS)
	{
		DbgPrint("CH910x_GpioSet 设置成功!");
	}
	else
	{
		DbgPrint("CH910x_GpioSet设置失败!");
	}
	return RetVal;
}

VOID CH348SetGpioLevel()
{
	UCHAR       GpioIndex = 0;     // GPIO序号掩码,位0-63
	UCHAR		GpioLevel = 0;      // GPIO电平掩码,与上iGpioMIndex位置对应。1:高电平,0:低电平	ULONG i;
	UCHAR RetVal;
	
	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取将设置的GPIO引脚

	if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioDir) == BST_CHECKED) //GPIO为输出时候才能设置电平状态
	{
		if(IsDlgButtonChecked(AfxMainHwnd,IDC_GpioLevel) == BST_CHECKED)
			GpioLevel =  0x01;
		else
			GpioLevel =  0x00;
	}
	else
	{
		MessageBox(AfxMainHwnd,"GPIO为输出时才能设置电平状态!","CH34xGpioCfg",MB_ICONERROR);
		DbgPrint("ERROR: GPIO为输出时候才能设置电平状态");
		return;
	}
		
	RetVal = CH348_GpioSet(hCom,&ChipPro,GpioIndex,GpioLevel); //设置某个GPIO的电平状态
	if(RetVal==CH910x_SUCCESS)//更新GPIO状态
	{
		DbgPrint("CH348_GpioSet电平设置成功!");
		SendDlgItemMessage(AfxMainHwnd,IDC_GetGpioLevel,BM_CLICK,0,0);
		//SendDlgItemMessage(AfxMainHwnd,IDC_GetChipCfg,BM_CLICK,0,0);
	}
	return;
}

//获取GPIO电平状态
VOID CH348GetGPIO()
{
	int GpioIndex;
	UCHAR	iGpioIndex;     // GPIO引脚序号,0-63
    UCHAR	GpioLevel = 0x00;	//对应引脚电平
	UCHAR	RetVal;

	GpioIndex = SendDlgItemMessage(AfxMainHwnd,IDC_Gpio,CB_GETCURSEL,0,0); //获取将设置的GPIO引脚
	
	iGpioIndex = GpioIndex; //获取GPIO引脚的序号0-63
	RetVal = CH348_GpioGet(hCom,&ChipPro,iGpioIndex,&GpioLevel); //获取某个GPIO引脚的电平状态
	if(RetVal==CH910x_SUCCESS)//更新GPIO状态
	{
		DbgPrint("CH348_GpioSet获取电平状态成功!");
		if(GpioLevel)
			CheckDlgButton(AfxMainHwnd,IDC_GpioLevel,BST_CHECKED);
		else
			CheckDlgButton(AfxMainHwnd,IDC_GpioLevel,BST_UNCHECKED);
	}
	else
	{
		DbgPrint("CH348_GpioSet获取电平状态失败!");
	}
	return;
}

//应用程序入口
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	return 	DialogBox(hInstance, (LPCTSTR)IDD_MainWnd, 0, (DLGPROC)WndProc);
}

//主窗体进程
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message)
	{

	case WM_INITDIALOG:
		{
			AfxMainHwnd = hWnd;
			//串口初始化
			GetComFriendlyName();	
			{//添加alt+tab切换时显示的图标
				HICON hicon;
				hicon = (HICON)LoadIcon(AfxMainIns,(LPCTSTR)IDI_Main);
				PostMessage(AfxMainHwnd,WM_SETICON,ICON_BIG,(LPARAM)(HICON)hicon);
				PostMessage(AfxMainHwnd,WM_SETICON,ICON_SMALL,(LPARAM)(HICON)hicon);
			}
			SendDlgItemMessage(hWnd,IDC_ShowMessage,EM_LIMITTEXT,0xFFFFFFFF,0);
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam); 
		wmEvent = HIWORD(wParam); 
		switch (wmId)
		{
		case IDC_Refresh:
			{
				//刷新串口
				SendDlgItemMessage(hWnd,IDC_AllCom,CB_RESETCONTENT,0,0); //清除组合框列表
				GetComFriendlyName();
			}
			break;
		case IDC_OpenCloseUART:
			{
				CHAR TempBuf[64] = "";
				//打开串口
				GetDlgItemText(hWnd,IDC_OpenCloseUART,TempBuf,sizeof(TempBuf));
				if(!strcmp("打开串口",TempBuf))
				{
					if(!OpenCom())
					{
						EnableWindow(GetDlgItem(hWnd,IDC_Refresh),TRUE);
						return TRUE;
					}	
					SetDlgItemText(hWnd,IDC_OpenCloseUART,"关闭串口");
					EnableWindow(GetDlgItem(hWnd,IDC_Refresh),FALSE);
					GetChipInfo();
					InsertGPIO();
					if(ChipPro.ChipType == USER_TYPE_CH348L || ChipPro.ChipType == USER_TYPE_CH348Q)
						CH348ReadGpioConfig();
					else
						CH910xReadGpioConfig();
				}
				else
				{
					CloseCom();
					SetDlgItemText(hWnd,IDC_OpenCloseUART,"打开串口");
					EnableWindow(GetDlgItem(hWnd,IDC_Refresh),TRUE);
					SetDlgItemText(hWnd,IDC_DevInfo,"");
					SetDlgItemText(AfxMainHwnd,1300,"GPIO设置");
					SendDlgItemMessage(hWnd,IDC_Gpio,CB_RESETCONTENT,0,0);
				}

			}
			break;
		case IDC_GetChipCfg:
			{//读取GPIO配置
				if(ChipPro.ChipType == USER_TYPE_CH348L || ChipPro.ChipType == USER_TYPE_CH348Q)
					CH348ReadGpioConfig();
				else
					CH910xReadGpioConfig();
			}
			break;
		case IDC_SetChipGpio:
			{//设置GPIO状态输入或输出
				if(ChipPro.ChipType == USER_TYPE_CH348L || ChipPro.ChipType == USER_TYPE_CH348Q)
					CH348GpioConfig();
				else
					CH910xGpioConfig(); 
			}
			break;
		case IDC_SetGpioLevel:
			{//设置GPIO电平
				if(ChipPro.ChipType == USER_TYPE_CH348L || ChipPro.ChipType == USER_TYPE_CH348Q)
					CH348SetGpioLevel();
				else
					CH910xSetGpioLevel(); 
			}
			break;
		case IDC_GetGpioLevel:
			{//获取GPIO电平
				if(ChipPro.ChipType == USER_TYPE_CH348L || ChipPro.ChipType == USER_TYPE_CH348Q)
					CH348GetGPIO();
				else
					SendDlgItemMessage(hWnd,IDC_GetChipCfg,BM_CLICK,0,0);
			}
			break;
		case IDC_ClearInfo:
			//清除输出信息
			SetDlgItemText(hWnd,IDC_ShowMessage,"");
			break;
		case WM_DESTROY:
			if(INVALID_HANDLE_VALUE != hCom)
			{
				CloseHandle(hCom);
				hCom = INVALID_HANDLE_VALUE;
			}
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;		
	}
	return 0;
}

总结

本文主要介绍如何使用CH343PT库中的GPIO设置函数,去设置GPIO的IO方向:输入或输出,设置GPIO电平状态(IO方向为输出时候可以设置该状态),以及获取GPIO电平状态等GPIO操作。

我想利用pyqt5在pycharm上将单片机上采集到的血氧信号进行滤波和显示,并最终生成一个类似于app的交互页面实时显示。目前我需要将单片机采集到的信号波形在我用pyqt创建的页面上显示,我之前已经将单片机采集到的信号传给了上位机,这是单片机部分的相关代码供你参考:main: #include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "key.h" #include "beep.h" #include "relay.h" #include "touch_key.h" #include "bmp.h" #include "oled.h" #include "adc.h" #include "stm32f10x.h" // 全局变量 volatile uint16_t red_value = 0; // 红光ADC值 volatile uint16_t ir_value = 0; // 红外光ADC值 volatile uint8_t data_ready = 0; // 数据就绪标志 // 状态机枚举 typedef enum { STATE_SET_RED = 0, STATE_WAIT_RED, STATE_SAMPLE_RED, STATE_SET_IR, STATE_WAIT_IR, STATE_SAMPLE_IR } SampleState_t; volatile SampleState_t sample_state = STATE_SET_RED; // 定时器3初始化(2kHz频率) void TIM3_Int_Init(uint16_t arr, uint16_t psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟 // 初始化TIM3定时器 TIM_TimeBaseStructure.TIM_Period = arr; // 自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频器 TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // 使能更新中断 // 配置NVIC中断 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3, ENABLE); // 使能定时器3 } // PB0和PB1初始化函数 void LED_Control_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始状态:关闭所有LED GPIO_SetBits(GPIOB, GPIO_Pin_0); GPIO_SetBits(GPIOB, GPIO_Pin_1); } int main(void) { // 初始化各模块 delay_init(); CORE_LED_Init(); CORE_LED_On(); led_init(); key_init(); beep_init(); relay_init(); OLED_Init(); Adc_Init(); uart_init(115200); LED_Control_Init(); // 初始化光源控制引脚 printf("System Start...\r\n"); printf("Red and IR Light Sampling System Ready\r\n"); // 初始化定时器3为2kHz频率 // 计算公式: 72MHz / (71+1) / (49+1) = 2000Hz TIM3_Int_Init(49, 71); while(1) { // 检测数据是否就绪 if(data_ready) { // 按照方案A格式发送数据: R:红光值,I:红外光值 printf("R:%d,I:%d\n", red_value, ir_value); data_ready = 0; } // 添加短暂延时,避免发送过快 delay_ms(2); // // 可选:添加按键检测等其他功能 // uint8_t key = key_scan(0); // if(key) { // // 处理按键 // } } } // TIM3中断服务函数(2kHz频率) void TIM3_IRQHandler(void) { static uint8_t settle_count = 0; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中断标志 switch(sample_state) { case STATE_SET_RED: // 设置红光:PB0=0, PB1=1 GPIO_ResetBits(GPIOB, GPIO_Pin_0); GPIO_SetBits(GPIOB, GPIO_Pin_1); sample_state = STATE_WAIT_RED; settle_count = 3; // 等待1.5ms稳定 (500us × 3) break; case STATE_WAIT_RED: if(--settle_count == 0) { sample_state = STATE_SAMPLE_RED; } break; case STATE_SAMPLE_RED: red_value = Get_Adc_Average(ADC_Channel_1, 3); sample_state = STATE_SET_IR; break; case STATE_SET_IR: // 设置红外光:PB0=1, PB1=0 GPIO_SetBits(GPIOB, GPIO_Pin_0); GPIO_ResetBits(GPIOB, GPIO_Pin_1); sample_state = STATE_WAIT_IR; settle_count = 3; // 等待1.5ms稳定 break; case STATE_WAIT_IR: if(--settle_count == 0) { sample_state = STATE_SAMPLE_IR; } break; case STATE_SAMPLE_IR: ir_value = Get_Adc_Average(ADC_Channel_1, 3); sample_state = STATE_SET_RED; data_ready = 1; // 一对数据采集完成 break; } } } adc.c: #include "adc.h" #include "delay.h" // 初始化ADC // 这里我们仅以规则通道为例 // 我们默认将开启通道0~3 void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1通道时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M // PA1 作为模拟通道输入引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入引脚 GPIO_Init(GPIOA, &GPIO_InitStructure); ADC_DeInit(ADC1); // 复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ADC工作模式:ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 模数转换工作在单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 模数转换工作在单次转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 转换由软件而不是外部触发启动 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ADC数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; // 顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); // 根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_Cmd(ADC1, ENABLE); // 使能指定的ADC1 ADC_ResetCalibration(ADC1); // 使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); // 等待复位校准结束 ADC_StartCalibration(ADC1); // 开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); // 等待校准结束 } // 获得ADC值 // ch: 通道值 0~3 uint16_t Get_Adc(u8 ch) { // 设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); // ADC1,ADC通道,采样时间为239.5周期 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换结束 return ADC_GetConversionValue(ADC1); // 返回最近一次ADC1规则组的转换结果 } // 获取ADC多次采样的平均值 uint16_t Get_Adc_Average(u8 ch, u8 times) { u32 temp_val = 0; u8 t; for(t = 0; t < times; t++) { temp_val += Get_Adc(ch); } return temp_val / times; } usart.c: #include "sys.h" #include "usart.h" ////////////////////////////////////////////////////////////////////////////////// //如果使用ucos,则包括下面的头文件即可. #if SYSTEM_SUPPORT_OS #include "includes.h" //ucos 使用 #endif ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准需要的支持函数 struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 void _sys_exit(int x) { x = x; } //重定义fputc函数 int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch; } #endif #if EN_USART1_RX //如果使能了接收 //串口1中断服务程序 //注意,读取USARTx->SR能避免莫名其妙的错误 u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节. //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0, 接收到的有效字节数目 u16 USART_RX_STA=0; //接收状态标记 void uart_init(u32 bound){ //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; SystemInit(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟 //USART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器 //USART 初始化设置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断 USART_Cmd(USART1, ENABLE); //使能串口1 } void USART1_SendByte(u8 data) { USART_SendData(USART1, data); // 发送数据 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // 等待发送完成 } void USART1_SendString(char *str) { u8 i = 0; while (str[i] != '\0') { USART1_SendByte(str[i]); i++; // delay_ms(1); // 适当延时避免发送冲突 } } void USART1_IRQHandler(void) //串口1中断服务程序 { u8 Res; #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) { Res =USART_ReceiveData(USART1); //读取接收到的数据 if((USART_RX_STA&0x8000)==0)//接收未完成 { if(USART_RX_STA&0x4000)//接收到了0x0d { if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始 else USART_RX_STA|=0x8000; //接收完成了 } else //还没收到0X0D { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } } } } #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS. OSIntExit(); #endif } #endif 这是我搭建的ui代码: <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>1295</width> <height>967</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0" colspan="2"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QLabel" name="label_7"> <property name="styleSheet"> <string notr="true">font: 14pt "华文宋体";</string> </property> <property name="text"> <string>最低血氧饱和度:</string> </property> </widget> </item> <item> <widget class="QLabel" name="label_8"> <property name="styleSheet"> <string notr="true">font: 14pt "华文宋体";</string> </property> <property name="text"> <string>平均血氧饱和度:</string> </property> </widget> </item> <item> <widget class="QLabel" name="label_9"> <property name="styleSheet"> <string notr="true">font: 14pt "华文宋体";</string> </property> <property name="text"> <string>心率:</string> </property> </widget> </item> </layout> </item> <item row="2" column="0"> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> <widget class="QPushButton" name="btn_start_2"> <property name="styleSheet"> <string notr="true">font: 12pt "华文宋体";</string> </property> <property name="text"> <string>开始采集</string> </property> </widget> </item> <item> <widget class="QPushButton" name="btn_save_2"> <property name="styleSheet"> <string notr="true">font: 12pt "华文宋体";</string> </property> <property name="text"> <string>保存数据</string> </property> </widget> </item> </layout> </item> <item row="2" column="2"> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <layout class="QVBoxLayout" name="verticalLayout_4"> <item> <widget class="QLabel" name="label_2"> <property name="styleSheet"> <string notr="true">font: 10pt "华文宋体";</string> </property> <property name="text"> <string>界面设置</string> </property> </widget> </item> <item> <widget class="QComboBox" name="comboBox_2"> <item> <property name="text"> <string>只显示原始信号</string> </property> </item> <item> <property name="text"> <string>只显示滤波后信号</string> </property> </item> <item> <property name="text"> <string>显示所有信号</string> </property> </item> </widget> </item> </layout> </item> <item> <layout class="QVBoxLayout" name="verticalLayout_5"> <item> <widget class="QLabel" name="label_5"> <property name="styleSheet"> <string notr="true">font: 11pt "华文宋体";</string> </property> <property name="text"> <string>串口</string> </property> </widget> </item> <item> <widget class="QComboBox" name="combo_serial_port_2"/> </item> </layout> </item> <item> <layout class="QVBoxLayout" name="verticalLayout_6"> <item> <widget class="QLabel" name="label_6"> <property name="styleSheet"> <string notr="true">font: 11pt "华文宋体";</string> </property> <property name="text"> <string>波特率</string> </property> </widget> </item> <item> <widget class="QComboBox" name="combo_baudrate_2"> <property name="contextMenuPolicy"> <enum>Qt::DefaultContextMenu</enum> </property> <property name="maxVisibleItems"> <number>12</number> </property> <property name="duplicatesEnabled"> <bool>false</bool> </property> <item> <property name="text"> <string>9600</string> </property> </item> <item> <property name="text"> <string>115200</string> </property> </item> <item> <property name="text"> <string>57600</string> </property> </item> </widget> </item> </layout> </item> </layout> </item> <item row="3" column="1"> <widget class="QSlider" name="slider_lowpass"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> </widget> </item> <item row="1" column="0" colspan="3"> <widget class="QtCharts::QChartView" name="graphicsView_signal"/> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>1295</width> <height>26</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <customwidgets> <customwidget> <class>QtCharts::QChartView</class> <extends>QGraphicsView</extends> <header>qchartview.h</header> </customwidget> </customwidgets> <resources/> <connections/> </ui> 这是·我的ui文件转换为py后的代码,名为change.py:# -*- coding: utf-8 -*- Form implementation generated from reading ui file ‘change.ui’ Created by: PyQt5 UI code generator 5.15.9 WARNING: Any manual changes made to this file will be lost when pyuic5 is run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName(“MainWindow”) MainWindow.resize(1295, 967) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName(“centralwidget”) self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName(“gridLayout”) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName(“horizontalLayout”) self.label_7 = QtWidgets.QLabel(self.centralwidget) self.label_7.setStyleSheet(“font: 14pt "华文宋体";”) self.label_7.setObjectName(“label_7”) self.horizontalLayout.addWidget(self.label_7) self.label_8 = QtWidgets.QLabel(self.centralwidget) self.label_8.setStyleSheet(“font: 14pt "华文宋体";”) self.label_8.setObjectName(“label_8”) self.horizontalLayout.addWidget(self.label_8) self.label_9 = QtWidgets.QLabel(self.centralwidget) self.label_9.setStyleSheet(“font: 14pt "华文宋体";”) self.label_9.setObjectName(“label_9”) self.horizontalLayout.addWidget(self.label_9) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName(“horizontalLayout_3”) self.btn_start_2 = QtWidgets.QPushButton(self.centralwidget) self.btn_start_2.setStyleSheet(“font: 12pt "华文宋体";”) self.btn_start_2.setObjectName(“btn_start_2”) self.horizontalLayout_3.addWidget(self.btn_start_2) self.btn_save_2 = QtWidgets.QPushButton(self.centralwidget) self.btn_save_2.setStyleSheet(“font: 12pt "华文宋体";”) self.btn_save_2.setObjectName(“btn_save_2”) self.horizontalLayout_3.addWidget(self.btn_save_2) self.gridLayout.addLayout(self.horizontalLayout_3, 2, 0, 1, 1) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName(“horizontalLayout_4”) self.verticalLayout_4 = QtWidgets.QVBoxLayout() self.verticalLayout_4.setObjectName(“verticalLayout_4”) self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setStyleSheet(“font: 10pt "华文宋体";”) self.label_2.setObjectName(“label_2”) self.verticalLayout_4.addWidget(self.label_2) self.comboBox_2 = QtWidgets.QComboBox(self.centralwidget) self.comboBox_2.setObjectName(“comboBox_2”) self.comboBox_2.addItem(“”) self.comboBox_2.addItem(“”) self.comboBox_2.addItem(“”) self.verticalLayout_4.addWidget(self.comboBox_2) self.horizontalLayout_4.addLayout(self.verticalLayout_4) self.verticalLayout_5 = QtWidgets.QVBoxLayout() self.verticalLayout_5.setObjectName(“verticalLayout_5”) self.label_5 = QtWidgets.QLabel(self.centralwidget) self.label_5.setStyleSheet(“font: 11pt "华文宋体";”) self.label_5.setObjectName(“label_5”) self.verticalLayout_5.addWidget(self.label_5) self.combo_serial_port_2 = QtWidgets.QComboBox(self.centralwidget) self.combo_serial_port_2.setObjectName(“combo_serial_port_2”) self.verticalLayout_5.addWidget(self.combo_serial_port_2) self.horizontalLayout_4.addLayout(self.verticalLayout_5) self.verticalLayout_6 = QtWidgets.QVBoxLayout() self.verticalLayout_6.setObjectName(“verticalLayout_6”) self.label_6 = QtWidgets.QLabel(self.centralwidget) self.label_6.setStyleSheet(“font: 11pt "华文宋体";”) self.label_6.setObjectName(“label_6”) self.verticalLayout_6.addWidget(self.label_6) self.combo_baudrate_2 = QtWidgets.QComboBox(self.centralwidget) self.combo_baudrate_2.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) self.combo_baudrate_2.setMaxVisibleItems(12) self.combo_baudrate_2.setDuplicatesEnabled(False) self.combo_baudrate_2.setObjectName(“combo_baudrate_2”) self.combo_baudrate_2.addItem(“”) self.combo_baudrate_2.addItem(“”) self.combo_baudrate_2.addItem(“”) self.verticalLayout_6.addWidget(self.combo_baudrate_2) self.horizontalLayout_4.addLayout(self.verticalLayout_6) self.gridLayout.addLayout(self.horizontalLayout_4, 2, 2, 1, 1) self.slider_lowpass = QtWidgets.QSlider(self.centralwidget) self.slider_lowpass.setOrientation(QtCore.Qt.Horizontal) self.slider_lowpass.setObjectName(“slider_lowpass”) self.gridLayout.addWidget(self.slider_lowpass, 3, 1, 1, 1) self.graphicsView_signal = QtChart.QChartView(self.centralwidget) self.graphicsView_signal.setObjectName(“graphicsView_signal”) self.gridLayout.addWidget(self.graphicsView_signal, 1, 0, 1, 3) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 1295, 26)) self.menubar.setObjectName(“menubar”) MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName(“statusbar”) MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label_7.setText(_translate("MainWindow", "最低血氧饱和度:")) self.label_8.setText(_translate("MainWindow", "平均血氧饱和度:")) self.label_9.setText(_translate("MainWindow", "心率:")) self.btn_start_2.setText(_translate("MainWindow", "开始采集")) self.btn_save_2.setText(_translate("MainWindow", "保存数据")) self.label_2.setText(_translate("MainWindow", "界面设置")) self.comboBox_2.setItemText(0, _translate("MainWindow", "只显示原始信号")) self.comboBox_2.setItemText(1, _translate("MainWindow", "只显示滤波后信号")) self.comboBox_2.setItemText(2, _translate("MainWindow", "显示所有信号")) self.label_5.setText(_translate("MainWindow", "串口")) self.label_6.setText(_translate("MainWindow", "波特率")) self.combo_baudrate_2.setItemText(0, _translate("MainWindow", "9600")) self.combo_baudrate_2.setItemText(1, _translate("MainWindow", "115200")) self.combo_baudrate_2.setItemText(2, _translate("MainWindow", "57600")) from PyQt5 import QtChart 我需要你将单片机发送的信号显示在Pycharm实现的界面上,注意界面的下拉框里我希望有以下可选项:显示红光,显示红外光。界面背景设计你可以自由发挥,希望有质感一点
最新发布
11-14
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PC技术小能手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值