单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31
HSE 为8MHZ
HSI为16MHZ
原理图:

主函数:
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336,8,2,7); /* 设置时钟, 168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
key_init(); /* 初始化按键 */
tp_dev.init(); /* 触摸屏初始化 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "TOUCH TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
if (tp_dev.touchtype != 0xFF)
{
lcd_show_string(30, 110, 200, 16, 16, "Press KEY0 to Adjust", RED); /* 电阻屏才显示 */
}
delay_ms(1500);
load_draw_dialog();
if (tp_dev.touchtype & 0x80)
{
ctp_test(); /* 电容屏测试 */
}
else
{
rtp_test(); /* 电阻屏测试 */
}
}
配置:
/* 电阻触摸屏驱动IC T_PEN/T_CS/T_MISO/T_MOSI/T_SCK 引脚 定义 */
#define T_PEN_GPIO_PORT GPIOH
#define T_PEN_GPIO_PIN GPIO_PIN_7
#define T_PEN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */
#define T_CS_GPIO_PORT GPIOG
#define T_CS_GPIO_PIN GPIO_PIN_1
#define T_CS_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */
#define T_MISO_GPIO_PORT GPIOD
#define T_MISO_GPIO_PIN GPIO_PIN_11
#define T_MISO_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */
#define T_MOSI_GPIO_PORT GPIOH
#define T_MOSI_GPIO_PIN GPIO_PIN_8
#define T_MOSI_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */
#define T_CLK_GPIO_PORT GPIOH
#define T_CLK_GPIO_PIN GPIO_PIN_6
#define T_CLK_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */
/******************************************************************************************/
/* 电阻触摸屏控制引脚 */
#define T_PEN HAL_GPIO_ReadPin(T_PEN_GPIO_PORT, T_PEN_GPIO_PIN) /* T_PEN */
#define T_MISO HAL_GPIO_ReadPin(T_MISO_GPIO_PORT, T_MISO_GPIO_PIN) /* T_MISO */
#define T_MOSI(x) do{ x ? \
HAL_GPIO_WritePin(T_MOSI_GPIO_PORT, T_MOSI_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(T_MOSI_GPIO_PORT, T_MOSI_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* T_MOSI */
#define T_CLK(x) do{ x ? \
HAL_GPIO_WritePin(T_CLK_GPIO_PORT, T_CLK_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(T_CLK_GPIO_PORT, T_CLK_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* T_CLK */
#define T_CS(x) do{ x ? \
HAL_GPIO_WritePin(T_CS_GPIO_PORT, T_CS_GPIO_PIN, GPIO_PIN_SET) : \
HAL_GPIO_WritePin(T_CS_GPIO_PORT, T_CS_GPIO_PIN, GPIO_PIN_RESET); \
}while(0) /* T_CS */
#define TP_PRES_DOWN 0x8000 /* 触屏被按下 */
#define TP_CATH_PRES 0x4000 /* 有按键按下了 */
#define CT_MAX_TOUCH 10 /* 电容屏支持的点数,固定为5点 */
/* 触摸屏控制器 */
typedef struct
{
uint8_t (*init)(void); /* 初始化触摸屏控制器 */
uint8_t (*scan)(uint8_t); /* 扫描触摸屏.0,屏幕扫描;1,物理坐标; */
void (*adjust)(void); /* 触摸屏校准 */
uint16_t x[CT_MAX_TOUCH]; /* 当前坐标 */
uint16_t y[CT_MAX_TOUCH]; /* 电容屏有最多10组坐标,电阻屏则用x[0],y[0]代表:此次扫描时,触屏的坐标,用
* x[9],y[9]存储第一次按下时的坐标.
*/
uint16_t sta; /* 笔的状态
* b15:按下1/松开0;
* b14:0,没有按键按下;1,有按键按下.
* b13~b10:保留
* b9~b0:电容触摸屏按下的点数(0,表示未按下,1表示按下)
*/
/* 5点校准触摸屏校准参数(电容屏不需要校准) */
float xfac; /* 5点校准法x方向比例因子 */
float yfac; /* 5点校准法y方向比例因子 */
short xc; /* 中心X坐标物理值(AD值) */
short yc; /* 中心Y坐标物理值(AD值) */
/* 新增的参数,当触摸屏的左右上下完全颠倒时需要用到.
* b0:0, 竖屏(适合左右为X坐标,上下为Y坐标的TP)
* 1, 横屏(适合左右为Y坐标,上下为X坐标的TP)
* b1~6: 保留.
* b7:0, 电阻屏
* 1, 电容屏
*/
uint8_t touchtype;
} _m_tp_dev;
uint8_t tp_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
tp_dev.touchtype = 0; /* 默认设置(电阻屏 & 竖屏) */
tp_dev.touchtype |= lcddev.dir & 0X01; /* 根据LCD判定是横屏还是竖屏 */
if (lcddev.id == 0x7796) /* 3.5寸屏有两种,一种屏幕ID为0x5510带电阻触摸屏,一种屏幕ID为0x7796带GT型号的电容触摸屏 */
{
if (gt9xxx_init() == 0) /* 初始化GT系列触摸屏成功,即当前3.5寸屏为电容触摸屏 */
{
tp_dev.scan = gt9xxx_scan; /* 扫描函数指向GT9147触摸屏扫描 */
tp_dev.touchtype |= 0X80; /* 电容屏 */
return 0;
}
}
if (lcddev.id == 0X5510 || lcddev.id == 0X9806 || lcddev.id == 0X4342 || lcddev.id == 0X4384 || lcddev.id == 0X1018) /* 电容触摸屏,4.3寸/10.1寸屏 */
{
gt9xxx_init();
tp_dev.scan = gt9xxx_scan; /* 扫描函数指向GT9147触摸屏扫描 */
tp_dev.touchtype |= 0X80; /* 电容屏 */
return 0;
}
return 1;
}
uint8_t gt9xxx_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
uint8_t temp[5];
GT9XXX_RST_GPIO_CLK_ENABLE(); /* RST引脚时钟使能 */
GT9XXX_INT_GPIO_CLK_ENABLE(); /* INT引脚时钟使能 */
gpio_init_struct.Pin = GT9XXX_RST_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
HAL_GPIO_Init(GT9XXX_RST_GPIO_PORT, &gpio_init_struct); /* 初始化RST引脚 */
gpio_init_struct.Pin = GT9XXX_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
HAL_GPIO_Init(GT9XXX_INT_GPIO_PORT, &gpio_init_struct); /* 初始化INT引脚 */
ct_iic_init(); /* 初始化电容屏的I2C总线 */
GT9XXX_RST(0); /* 复位 */
delay_ms(10);
GT9XXX_RST(1); /* 释放复位 */
delay_ms(10);
/* INT引脚模式设置, 输入模式, 浮空输入 */
gpio_init_struct.Pin = GT9XXX_INT_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */
gpio_init_struct.Pull = GPIO_NOPULL; /* 不带上下拉,浮空模式 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
HAL_GPIO_Init(GT9XXX_INT_GPIO_PORT, &gpio_init_struct); /* 初始化INT引脚 */
delay_ms(100);
gt9xxx_rd_reg(GT9XXX_PID_REG, temp, 4); /* 读取触摸IC的ID */
temp[4] = 0;
/* 判断一下是否是特定的触摸屏 */
if ( strcmp((char *)temp, "911") && strcmp((char *)temp, "9147") && strcmp((char *)temp, "1158") && strcmp((char *)temp, "9271"))
{
return 1; /* 若不是触摸屏用到的GT911/9147/1158/9271,则初始化失败,需硬件查看触摸IC型号以及查看时序函数是否正确 */
}
printf("CTP ID:%s\r\n", temp); /* 打印ID */
if (strcmp((char *)temp, "9271") == 0) /* ID==9271, 支持10点触摸 */
{
g_gt_tnum = 10; /* 支持10点触摸屏 */
}
temp[0] = 0X02;
gt9xxx_wr_reg(GT9XXX_CTRL_REG, temp, 1); /* 软复位GT9XXX */
delay_ms(10);
temp[0] = 0X00;
gt9xxx_wr_reg(GT9XXX_CTRL_REG, temp, 1); /* 结束复位, 进入读坐标状态 */
return 0;
}
uint8_t gt9xxx_scan(uint8_t mode)
{
uint8_t buf[4];
uint8_t i = 0;
uint8_t res = 0;
uint16_t temp;
uint16_t tempsta;
static uint8_t t = 0; /* 控制查询间隔,从而降低CPU占用率 */
t++;
if ((t % 10) == 0 || t < 10) /* 空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率 */
{
gt9xxx_rd_reg(GT9XXX_GSTID_REG, &mode, 1); /* 读取触摸点的状态 */
if ((mode & 0x80) && ((mode & 0XF) <= g_gt_tnum))
{
i = 0;
gt9xxx_wr_reg(GT9XXX_GSTID_REG, &i, 1); /* 清标志 */
}
if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum))
{
temp = 0XFFFF << (mode & 0XF); /* 将点的个数转换为1的位数,匹配tp_dev.sta定义 */
tempsta = tp_dev.sta; /* 保存当前的tp_dev.sta值 */
tp_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES;
tp_dev.x[g_gt_tnum - 1] = tp_dev.x[0]; /* 保存触点0的数据,保存在最后一个上 */
tp_dev.y[g_gt_tnum - 1] = tp_dev.y[0];
for (i = 0; i < g_gt_tnum; i++)
{
if (tp_dev.sta & (1 << i)) /* 触摸有效? */
{
gt9xxx_rd_reg(GT9XXX_TPX_TBL[i], buf, 4); /* 读取XY坐标值 */
if (lcddev.id == 0X5510 || lcddev.id == 0X9806 || lcddev.id == 0X7796) /* 4.3寸800*480 和 3.5寸480*320 MCU屏 */
{
if (tp_dev.touchtype & 0X01) /* 横屏 */
{
tp_dev.x[i] = lcddev.width - (((uint16_t)buf[3] << 8) + buf[2]);
tp_dev.y[i] = ((uint16_t)buf[1] << 8) + buf[0];
}
else
{
tp_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0];
tp_dev.y[i] = ((uint16_t)buf[3] << 8) + buf[2];
}
}
else /* 其他型号 */
{
if (tp_dev.touchtype & 0X01) /* 横屏 */
{
tp_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0];
tp_dev.y[i] = ((uint16_t)buf[3] << 8) + buf[2];
}
else
{
tp_dev.x[i] = lcddev.width - (((uint16_t)buf[3] << 8) + buf[2]);
tp_dev.y[i] = ((uint16_t)buf[1] << 8) + buf[0];
}
}
//printf("x[%d]:%d,y[%d]:%d\r\n", i, tp_dev.x[i], i, tp_dev.y[i]);
}
}
res = 1;
if (tp_dev.x[0] > lcddev.width || tp_dev.y[0] > lcddev.height) /* 非法数据(坐标超出了) */
{
if ((mode & 0XF) > 1) /* 有其他点有数据,则复第二个触点的数据到第一个触点. */
{
tp_dev.x[0] = tp_dev.x[1];
tp_dev.y[0] = tp_dev.y[1];
t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
else /* 非法数据,则忽略此次数据(还原原来的) */
{
tp_dev.x[0] = tp_dev.x[g_gt_tnum - 1];
tp_dev.y[0] = tp_dev.y[g_gt_tnum - 1];
mode = 0X80;
tp_dev.sta = tempsta; /* 恢复tp_dev.sta */
}
}
else
{
t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */
}
}
}
if ((mode & 0X8F) == 0X80) /* 无触摸点按下 */
{
if (tp_dev.sta & TP_PRES_DOWN) /* 之前是被按下的 */
{
tp_dev.sta &= ~TP_PRES_DOWN; /* 标记按键松开 */
}
else /* 之前就没有被按下 */
{
tp_dev.x[0] = 0xffff;
tp_dev.y[0] = 0xffff;
tp_dev.sta &= 0XE000; /* 清除点有效标记 */
}
}
if (t > 240)t = 10; /* 重新从10开始计数 */
return res;
}
void ctp_test(void)
{
uint8_t t = 0;
uint8_t i = 0;
uint16_t lastpos[10][2]; /* 最后一次的数据 */
uint8_t maxp = 5;
if (lcddev.id == 0x1018)maxp = 10;
while (1)
{
tp_dev.scan(0);
for (t = 0; t < maxp; t++)
{
if ((tp_dev.sta) & (1 << t))
{
if (tp_dev.x[t] < lcddev.width && tp_dev.y[t] < lcddev.height) /* 坐标在屏幕范围内 */
{
if (lastpos[t][0] == 0xFFFF)
{
lastpos[t][0] = tp_dev.x[t];
lastpos[t][1] = tp_dev.y[t];
}
lcd_draw_bline(lastpos[t][0], lastpos[t][1], tp_dev.x[t], tp_dev.y[t], 2, POINT_COLOR_TBL[t]); /* 画线 */
lastpos[t][0] = tp_dev.x[t];
lastpos[t][1] = tp_dev.y[t];
if (tp_dev.x[t] > (lcddev.width - 24) && tp_dev.y[t] < 20)
{
load_draw_dialog(); /* 清除 */
}
}
}
else
{
lastpos[t][0] = 0xFFFF;
}
}
delay_ms(5);
i++;
if (i % 20 == 0)
{
LED0_TOGGLE();
}
}
}
debug:

测试结果:
