(已解决)移植例程16个触摸按键16个灯-8个共阴-8个共阳数码管显示程序失败,不知道是
本帖最后由 xxkj2010 于 2023-12-29 10:45 编辑单片机使用STC8H1K17T,程序从例程16个触摸按键16个灯-8个共阴-8个共阳数码管显示程序中修改,
当前目的是想用触摸开关控制接在P54的LED灯亮灭,
移植失败,不知道是硬件问题还是软件问题,请大佬赐教,谢谢!
你先把原理图,PCB, 源程序,按3个楼层贴出来,大家一起来帮忙 主要电路原理图
PCB
/*
单片机:STC8H1K17T
使用触摸引脚:TK3、TK6、TK7
*/
#include "STC8Hxxx.h"
#include <intrins.h>
#include <stdio.h>
/************* 功能说明 *************
读取16个触摸按键
触摸按键的读数本来是16位的, 由于使用了滤波算法, 滤波后数据为14位的.
参考电容的选取, 未按键时读数是满量程的1/3~1/2比较好, 兼顾灵敏度, 量产时又允许一定的平偏差.
程序会做缓慢的0点跟踪, 所以本例不合适长按处理, 长按处理还要有别的算法.
P1.0-->TK0,P1.1-->TK1, P5.4-->TK2, P1.3-->TK3, P1.4-->TK4,P1.5-->TK5, P1.6-->TK6, P1.7-->TK7,
P5.0-->TK8,P5.1-->TK9, P5.2-->TK1, P5.3-->TK1, P0.0-->TK1,P0.1-->TK1, P0.2-->TK1, P0.3-->TK1,
******************************************/
/************* 本地常量声明 **************/
#define DIS_BLACK 0x1A
#define DIS_ 0x1B
#define LED P54 //LED
#define ws2812b_IO P35 //WS2812信号输入口
#define MAIN_Fosc 24000000L //定义主时钟 11059200
#define BAUD (65536 - MAIN_Fosc/4/115200) //定义串口波特率重装值
bit fBusy; //串口发送忙标志
/************* 本地变量声明 **************/
u16 xdata TK_cnt; // 键计数值
u16 xdata TK_zero; // 0点读数
u16 KeyState; //键状态
u8 KeyCode; //键码 1~16
bit B_TK_Lowpass; //允许低通
bit B_ReadKeyOk; //标志已转换完成16个键
u8 TrigLimit; //触发转换限时
u8 KeyValue; //显示参数的键号, 0~15
u8 read_cnt;
/************* 本地函数声明 **************/
voiddelay_ms(u8 ms);
u8 CheckKey(u16 j);
/****************外部函数声明和外部变量声明 *****************/
u16 code T_KeyState = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// u16 code T_KeyPress = {400,300,200,200, 400,300,200,200, 400,300,200,200, 400,300,200,200}; //读数无平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
u16 code T_KeyPress = {200,150,100,100, 200,150,100,100, 200,150,100,100, 200,150,100,100}; //读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
/**********************************************/
void main(void)
{
u8 i;
u16 j;
fBusy = 0;
P_SW2 |= 0x80; //允许访问XSFR(扩展特殊功能寄存器)
// XOSCCR = 0xc0; //启动外部晶振
// while (!(XOSCCR & 1)); //等待时钟稳定
// CLKDIV = 0x00; //时钟不分频
// CKSEL = 0x01; //选择外部晶振
P0M0 = 0x00; P0M1 = 0x00;
// P1M0 = 0x00; P1M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P5M0 = 0x10; P5M1 = 0x00;
AUXR = 0x40; //使用定时器1作为串口波特率发生器
TMOD = 0x00;
TL1 = BAUD;
TH1 = BAUD >> 8;
TR1 = 1;
SCON = 0x50;
ES = 1;
P1n_pure_input(0xff); //Touch Key设置为高阻
// TSCHEN = 0xffff; //TK0~TK15
TSCHEN1 = 0xff; //TK0~TK7
// TSCHEN2 = 0xff; //TK8~TK15
TSCFG1= (7<<4) + 6; //开关电容工作频率 = fosc/(2*(TSCFG1+1)), 放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最小3
TSCFG2= 1; //配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)1(1/2)2(5/8)3(3/4)
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, B7: TSGO,B6: SINGLE,B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
// TSRT = 0x00; //没有LED分时扫描
IE2 |= 0x80; //允许触摸按键中断
EA = 1;
delay_ms(50);
// B_TK_Lowpass = 0; //禁止低通滤波
B_TK_Lowpass = 1; //允许低通滤波
for(read_cnt=0; read_cnt<40; read_cnt++) //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
{
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, 4次平均, 读数大约为无平均的一半
TSCTRL = (1<<7) + (1<<6) +1; //开始扫描, 2次平均, 读数大约为无平均的一半
// TSCTRL = (1<<7) + (1<<6); //开始扫描, 只转换1次, 无平均
B_ReadKeyOk = 0;
for(i=0; i<100; i++)
{
if(B_ReadKeyOk) break;
delay_ms(1);
}
}
for(i=0; i<16; i++) TK_zero = TK_cnt; //保存0点
B_TK_Lowpass = 1; //允许低通
KeyState = 0;
read_cnt = 0;
B_ReadKeyOk = 0;
KeyValue = 10;
KeyCode = 0;
delay_ms(2000);
printf("开始测试----\r\n");
while (1)
{
delay_ms(1);
if(++TrigLimit >= 100) //触发转换
{
TrigLimit = 0;
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, 4次平均, 读数大约为无平均的一半
TSCTRL = (1<<7) + (1<<6) +1; //开始扫描, 2次平均, 读数大约为无平均的一半
// TSCTRL = (1<<7) + (1<<6); //开始扫描, 只转换1次, 无平均
}
if(B_ReadKeyOk) // 16个键都转换完毕
{
B_ReadKeyOk = 0;
TrigLimit = 100;
// printf("B_ReadKeyOk!\r\n");
j = KeyState; //读入上一次键状态
for(i=0; i<16; i++)
{
if(TK_zero > TK_cnt) //计算与0点的差值
{
TK_zero--; //缓慢0点跟随
if((TK_zero - TK_cnt) >= T_KeyPress/2) KeyState |=T_KeyState; // 大于按键读数变量的1/2就是按下
else if((TK_zero - TK_cnt) <= T_KeyPress/3) KeyState &= ~T_KeyState; // 小于按键读数变量的1/3就是释放
}
else
{
KeyState &= ~T_KeyState;
if((TK_cnt - TK_zero) > 100) TK_zero += 50; //差别很大, 则快速回0点
else TK_zero += 10; //差别不大, 则慢速回0点
}
}
j = (j ^ KeyState) & KeyState; //检测键是否按下
if(j != 0)
{
KeyCode = CheckKey(j); //计算键码 1~16
printf("KeyCode:%d\r\n",KeyCode);
if(KeyCode == 3)
{
LED=!LED;
}
}
}
}
}
/**********************************************/
voiddelay_ms(u8 ms)
{
u16 i;
do
{
i = MAIN_Fosc / 10000;
while(--i) ;
}while(--ms);
}
/****************** 检测 计算键码 **************************************/
u8 CheckKey(u16 j)
{
u8 i;
if(j == 0) return 0; //无键按下
for(i=0; i<16; i++)
{
if(j & 0x0001) break;
j >>= 1;
}
return (i+1); //键码1~16
}
u8 isr_index;
void AUXR_ISR(void) interrupt 13
{
u8 j;
switch(isr_index)
{
case 32: //0103H 波形发生器5 中断入口
//用户中断处理代码
break;
case 33: //010BH 波形发生器异常2 中断入口
//用户中断处理代码
break;
case 34: //0113H 波形发生器异常4 中断入口
//用户中断处理代码
break;
case 35: //011BH 触摸按键 中断入口
//用户中断处理代码
j = TSSTA2;
if(j & 0x40) //数据溢出, 错误处理(略)
{
TSSTA2 |= 0x40; //写1清零
}
if(j & 0x80) //扫描完成
{
j &= 0x0f;
TSSTA2 |= 0x80; //写1清零
if(!B_TK_Lowpass) TK_cnt = TSDAT/4; //保存某个通道的读数 无低通滤波
else TK_cnt = ((TK_cnt * 3)>>2) + TSDAT/16; //保存某个通道的读数 低通滤波
if(j == 15) B_ReadKeyOk = 1; //读完一次循环
}
break;
case 36: //0123H RTC 中断入口
//用户中断处理代码
break;
case 37: //012BH P0口中断入口
//用户中断处理代码
break;
case 38: //0133H P1口中断入口
//用户中断处理代码
break;
case 39: //013BH P2口中断入口
//用户中断处理代码
break;
case 40: //0143H P3口中断入口
//用户中断处理代码
break;
case 41: //014BH P4口中断入口
//用户中断处理代码
break;
case 42: //0153H P5口中断入口
//用户中断处理代码
break;
case 43: //015BH P6口中断入口
//用户中断处理代码
break;
case 44: //0163H P7口中断入口
//用户中断处理代码
break;
case 45: //016BH P8口中断入口
//用户中断处理代码
break;
case 46: //0173H P9口中断入口
//用户中断处理代码
break;
default:
break;
}
}
void uart_isr() interrupt 4
{
if (TI)
{
TI = 0;
fBusy = 0;
}
if (RI)
{
RI = 0;
// CheckCustomCmd(SBUF); //检测命令序列
}
}
char putchar(char dat) //重定义putchar系统函数
{
while (fBusy);
fBusy = 1;
SBUF = dat;
return dat;
}
本帖最后由 xxkj2010 于 2023-12-28 13:21 编辑
实物图:
自己弄好了,main代码如下:
/*
单片机:STC8H1K17T
使用触摸引脚:TK3、TK6、TK7
*/
#include "STC8Hxxx.h"
#include <intrins.h>
#include <stdio.h>
/************* 功能说明 *************
读取16个触摸按键
触摸按键的读数本来是16位的, 由于使用了滤波算法, 滤波后数据为14位的.
参考电容的选取, 未按键时读数是满量程的1/3~1/2比较好, 兼顾灵敏度, 量产时又允许一定的平偏差.
程序会做缓慢的0点跟踪, 所以本例不合适长按处理, 长按处理还要有别的算法.
P1.0-->TK0,P1.1-->TK1, P5.4-->TK2, P1.3-->TK3, P1.4-->TK4,P1.5-->TK5, P1.6-->TK6, P1.7-->TK7,
P5.0-->TK8,P5.1-->TK9, P5.2-->TK1, P5.3-->TK1, P0.0-->TK1,P0.1-->TK1, P0.2-->TK1, P0.3-->TK1,
******************************************/
/************* 本地常量声明 **************/
#define DIS_BLACK 0x1A
#define DIS_ 0x1B
#define LED P54 //LED
#define ws2812b_IO P35 //WS2812信号输入口
#define MAIN_Fosc 24000000L //定义主时钟 11059200
#define BAUD (65536 - MAIN_Fosc/4/115200) //定义串口波特率重装值
bit fBusy; //串口发送忙标志
u16 AUXR_ISR_YN=0;
/************* 本地变量声明 **************/
u16 xdata TK_cnt; // 键计数值
u16 xdata TK_zero; // 0点读数
u16 KeyState; //键状态
u8 KeyCode; //键码 1~16
bit B_TK_Lowpass; //允许低通
bit B_ReadKeyOk; //标志已转换完成16个键
u8 TrigLimit; //触发转换限时
u8 KeyValue; //显示参数的键号, 0~15
u8 read_cnt;
/************* 本地函数声明 **************/
voiddelay_ms(u8 ms);
u8 CheckKey(u16 j);
/****************外部函数声明和外部变量声明 *****************/
u16 code T_KeyState = {0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
// u16 code T_KeyPress = {400,300,200,200, 400,300,200,200, 400,300,200,200, 400,300,200,200}; //读数无平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
u16 code T_KeyPress = {200,150,100,100, 200,150,100,100, 200,150,100,100, 200,150,100,100}; //读数有平均, 这个值是各键触摸后的变化值, 由于分布电容不同, 所以各键读数变化量不同
/**********************************************/
void main(void)
{
u8 i;
u16 j;
fBusy = 0;
P_SW2 |= 0x80; //允许访问XSFR(扩展特殊功能寄存器)
// XOSCCR = 0xc0; //启动外部晶振
// while (!(XOSCCR & 1)); //等待时钟稳定
// CLKDIV = 0x00; //时钟不分频
// CKSEL = 0x01; //选择外部晶振
P0M0 = 0x00; P0M1 = 0x00;
// P1M0 = 0x00; P1M1 = 0x00;
P3M0 = 0x00; P3M1 = 0x00;
P5M0 = 0x10; P5M1 = 0x00;
AUXR = 0x40; //使用定时器1作为串口波特率发生器
TMOD = 0x00;
TL1 = BAUD;
TH1 = BAUD >> 8;
TR1 = 1;
SCON = 0x50;
ES = 1;
P1n_pure_input(0xff); //Touch Key设置为高阻
// TSCHEN = 0xffff; //TK0~TK15
TSCHEN1 = 0xff; //TK0~TK7
// TSCHEN2 = 0xff; //TK8~TK15
TSCFG1= (7<<4) + 6; //开关电容工作频率 = fosc/(2*(TSCFG1+1)), 放电时间(系统时钟周期数) 0(125) 1(250) 2(500) 3(1000) 4(2000) 5(2500) 6(5000) 7(7500) 最小3
TSCFG2= 1; //配置触摸按键控制器的内部参考电压(AVCC的分压比), 0(1/4)1(1/2)2(5/8)3(3/4)
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, B7: TSGO,B6: SINGLE,B5: TSWAIT, B4: TSWUCS, B3: TSDCEN, B2: TSWUEN, B1 B0: TSSAMP
// TSRT = 0x00; //没有LED分时扫描
IE2 |= 0x80; //允许触摸按键中断
EA = 1;
delay_ms(50);
// B_TK_Lowpass = 0; //禁止低通滤波
B_TK_Lowpass = 1; //允许低通滤波
for(read_cnt=0; read_cnt<40; read_cnt++) //读40次键, 将此值作为未触摸时的0点, 要求上电时不要触摸按键
{
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, 4次平均, 读数大约为无平均的一半
TSCTRL = (1<<7) + (1<<6) +1; //开始扫描, 2次平均, 读数大约为无平均的一半
// TSCTRL = (1<<7) + (1<<6); //开始扫描, 只转换1次, 无平均
B_ReadKeyOk = 0;
for(i=0; i<100; i++)
{
if(B_ReadKeyOk) break;
delay_ms(1);
}
}
for(i=0; i<16; i++) TK_zero = TK_cnt; //保存0点
B_TK_Lowpass = 1; //允许低通
KeyState = 0;
read_cnt = 0;
B_ReadKeyOk = 0;
KeyValue = 10;
KeyCode = 0;
delay_ms(2000);
printf("开始测试----\r\n");
while (1)
{
delay_ms(1);
if(AUXR_ISR_YN){printf("AUXR_ISR_YN=%d\r\n",AUXR_ISR_YN);AUXR_ISR_YN=0;}
if(++TrigLimit >= 100) //触发转换
{
TrigLimit = 0;
// TSCTRL = (1<<7) + (1<<6) +3; //开始扫描, 4次平均, 读数大约为无平均的一半
TSCTRL = (1<<7) + (1<<6) +1; //开始扫描, 2次平均, 读数大约为无平均的一半
// TSCTRL = (1<<7) + (1<<6); //开始扫描, 只转换1次, 无平均
}
if(B_ReadKeyOk) // 16个键都转换完毕
{
B_ReadKeyOk = 0;
TrigLimit = 100;
//printf("B_ReadKeyOk!\r\n");
j = KeyState; //读入上一次键状态
for(i=0; i<8; i++)
{
if(TK_zero > TK_cnt) //计算与0点的差值
{
TK_zero--; //缓慢0点跟随
if((TK_zero - TK_cnt) >= T_KeyPress/2)
KeyState |=T_KeyState; // 大于按键读数变量的1/2就是按下
else if((TK_zero - TK_cnt) <= T_KeyPress/3)
KeyState &= ~T_KeyState; // 小于按键读数变量的1/3就是释放
}
else
{
KeyState &= ~T_KeyState;
if((TK_cnt - TK_zero) > 100)
TK_zero += 50; //差别很大, 则快速回0点
else TK_zero += 10; //差别不大, 则慢速回0点
}
}
j = (j ^ KeyState) & KeyState; //检测键是否按下
if(j != 0)
{
KeyCode = CheckKey(j); //计算键码 1~8
printf("KeyCode:%d\r\n",(u16)KeyCode);
if(KeyCode == 4)
{
LED=!LED;
}
}
}
}
}
/**********************************************/
voiddelay_ms(u8 ms)
{
u16 i;
do
{
i = MAIN_Fosc / 10000;
while(--i) ;
}while(--ms);
}
/****************** 检测 计算键码 **************************************/
u8 CheckKey(u16 j)
{
u8 i;
if(j == 0) return 0; //无键按下
for(i=0; i<8; i++)
{
if(j & 0x0001) break;
j >>= 1;
}
return (i+1); //键码1~8
}
u8 isr_index;
void AUXR_ISR(void) interrupt 13
{
u8 j;
switch(isr_index)
{
case 32: //0103H 波形发生器5 中断入口
//用户中断处理代码
break;
case 33: //010BH 波形发生器异常2 中断入口
//用户中断处理代码
break;
case 34: //0113H 波形发生器异常4 中断入口
//用户中断处理代码
break;
case 35: //011BH 触摸按键 中断入口
//用户中断处理代码
j = TSSTA2;
if(j & 0x40) //数据溢出, 错误处理(略)
{
TSSTA2 |= 0x40; //写1清零
}
if(j & 0x80) //扫描完成
{
j &= 0x0f;
TSSTA2 |= 0x80; //写1清零
if(!B_TK_Lowpass) TK_cnt = TSDAT/4; //保存某个通道的读数 无低通滤波
else TK_cnt = ((TK_cnt * 3)>>2) + TSDAT/16; //保存某个通道的读数 低通滤波
if(j == 7) {B_ReadKeyOk = 1; //读完一次循环
}
}
break;
case 36: //0123H RTC 中断入口
//用户中断处理代码
break;
case 37: //012BH P0口中断入口
//用户中断处理代码
break;
case 38: //0133H P1口中断入口
//用户中断处理代码
break;
case 39: //013BH P2口中断入口
//用户中断处理代码
break;
case 40: //0143H P3口中断入口
//用户中断处理代码
break;
case 41: //014BH P4口中断入口
//用户中断处理代码
break;
case 42: //0153H P5口中断入口
//用户中断处理代码
break;
case 43: //015BH P6口中断入口
//用户中断处理代码
break;
case 44: //0163H P7口中断入口
//用户中断处理代码
break;
case 45: //016BH P8口中断入口
//用户中断处理代码
break;
case 46: //0173H P9口中断入口
//用户中断处理代码
break;
default:
break;
}
}
void uart_isr() interrupt 4
{
if (TI)
{
TI = 0;
fBusy = 0;
}
if (RI)
{
RI = 0;
// CheckCustomCmd(SBUF); //检测命令序列
}
}
char putchar(char dat) //重定义putchar系统函数
{
while (fBusy);
fBusy = 1;
SBUF = dat;
return dat;
}
xxkj2010 发表于 2023-12-29 10:38
自己弄好了,main代码如下:
这个可以直接烧录测试吗
STC8H1K17T
大佬
zpzobcna 发表于 2025-4-11 18:21
这个可以直接烧录测试吗
STC8H1K17T
大佬
自己试试吧,反正不行还可以重新下载,又不会损坏MCU
页:
[1]