在线时间151 小时
UID3129923
注册时间2015-5-21
NXP金币0
该用户从未签到
高级会员

- 积分
- 722
- 最后登录
- 2016-1-9
|
接上次的实验:https://www.nxpic.org.cn/module/forum/thread-600350-1-1.html
本次所测试模块为TSI的电容触摸按键,关于这里的TSI,里面涉及到了许多模拟电路的知识,我不是非常清楚,所以帖子里有错误的地方也请指出。
首先来看程序:
主函数:
int main (void)
{
INT16U Vout = 0;
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK
| SIM_SCGC5_PORTB_MASK
| SIM_SCGC5_PORTC_MASK
| SIM_SCGC5_PORTD_MASK
| SIM_SCGC5_PORTE_MASK
| SIM_SCGC5_TSI_MASK);
SystemCoreClockUpdate();
PORT_ENABLE_CLK(MKL_PORTB); /* 使能PORT时钟 */
PORT_ENABLE_CLK(MKL_PORTD);
IO_FUN_SEL(MKL_PORTB,18,1); /* IO功能选择 */
IO_FUN_SEL(MKL_PORTB,19,1);
IO_FUN_SEL(MKL_PORTD,1,1);
GPIO_DDR_OUTPUT(MKL_PORTB,18); /* IO设置为输出模式 */
GPIO_DDR_OUTPUT(MKL_PORTB,19);
GPIO_DDR_OUTPUT(MKL_PORTD,1);
GPIO_CLR(MKL_PORTB,18); /* IO设置为高电平,LED熄灭 */
GPIO_SET(MKL_PORTB,19);
GPIO_SET(MKL_PORTD,1);
TSI_Init();
NVIC_EnableIRQ(TSI0_IRQn);
NVIC_SetPriority(TSI0_IRQn,3); /**< TSI0 interrupt */
while (1){
TSI_Slider_LED();
}
}
主函数中关于这个模块我们主要关心的就是上面红色的部分:TSI的初始化, TSI控制LED。
TSI初始化:
SIM_SCGC5 |= SIM_SCGC5_TSI_MASK; // Enable clock gating for TSI
/* Enable proper GPIO as TSI channels */
PORTB_PCR16 = PORT_PCR_MUX(0); // PTB16 as TSI channel 9
PORTB_PCR17 = PORT_PCR_MUX(0); // PTB17 as TSI channel 10
PORTC_PCR0 = PORT_PCR_MUX(0); // PTB17 as TSI channel 13
NVIC_DisableIRQ((IRQn_Type)TSI0_IRQn);
TSI0_GENCS |= (TSI_GENCS_ESOR_MASK //允许扫描结束中断
| TSI_GENCS_MODE(0) //配置为电容传感模式
| TSI_GENCS_REFCHRG(4) //参考振荡器充放电电流值
| TSI_GENCS_DVOLT(0) //振荡器电压下限
| TSI_GENCS_EXTCHRG(7) //电极振荡器充放电电流值
| TSI_GENCS_PS(4) //电极振荡器分频数
| TSI_GENCS_NSCN(11) //电极采样次数
| TSI_GENCS_TSIIEN_MASK //TSI中断使能
| TSI_GENCS_STPE_MASK //开启低功耗模式正常工作
);
TSI0_GENCS |= TSI_GENCS_TSIEN_MASK; //使能TSI
TSI_SelfCalibration(); //TSI校准
}
在TSI配置里面提到了两个振荡器(暂且这么翻译),他们的区别如下:
电极振荡器是通过电量的变化值来控制TSI中断,从而达到触摸控制的目的。
参考振荡器是用来代替外部电容,给电极振荡器充电的。
TSI校准:
void TSI_SelfCalibration(void)
{
unsigned char cnt;
unsigned char trigger_backup;
TSI0_GENCS |= TSI_GENCS_EOSF_MASK; // Clear End of Scan Flag
TSI0_GENCS &= ~TSI_GENCS_TSIEN_MASK; // Disable TSI module
if(TSI0_GENCS & TSI_GENCS_STM_MASK) // Back-up TSI Trigger mode from Application
trigger_backup = TRUE;
else
trigger_backup = FALSE;
TSI0_GENCS &= ~TSI_GENCS_STM_MASK; // Use SW trigger
TSI0_GENCS &= ~TSI_GENCS_TSIIEN_MASK; // Enable TSI interrupts
TSI0_GENCS |= TSI_GENCS_TSIEN_MASK; // Enable TSI module
for(cnt=0; cnt < total_electrode; cnt++) // Get Counts when Electrode not pressed
{
TSI0_DATA = ((elec_array[cnt] << TSI_DATA_TSICH_SHIFT) );
TSI0_DATA |= TSI_DATA_SWTS_MASK;
while(!(TSI0_GENCS & TSI_GENCS_EOSF_MASK));
TSI0_GENCS |= TSI_GENCS_EOSF_MASK;
gu16Baseline[cnt] = (TSI0_DATA & TSI_DATA_TSICNT_MASK);
}
TSI0_GENCS &= ~TSI_GENCS_TSIEN_MASK; // Disable TSI module
TSI0_GENCS |= TSI_GENCS_TSIIEN_MASK; // Enale TSI interrupt
if(trigger_backup) // Restore trigger mode
TSI0_GENCS |= TSI_GENCS_STM_MASK;
else
TSI0_GENCS &= ~TSI_GENCS_STM_MASK;
TSI0_GENCS |= TSI_GENCS_TSIEN_MASK; // Enable TSI module
TSI0_DATA = ((elec_array[0]<<TSI_DATA_TSICH_SHIFT) ); //选择TSI通道0
TSI0_DATA |= TSI_DATA_SWTS_MASK;
}
程序看似复杂,实则实现的是:在未触摸电容按键时,读取当前的电流值来作为参考值。
只是在程序中的时序以及关闭和打开TSI的时机即可。
中断服务函数:
void TSI0_IRQHandler(void)
{
end_flag = TRUE;
TSI0_GENCS |= TSI_GENCS_EOSF_MASK; // Clear End of Scan Flag
change_electrode();
}
这就不多说了,置LED判断标志位,清采样完成标志位。
电极变化判断(change_electrode):
void change_electrode(void)
{
int16_t u16temp_delta;
gu16TSICount[ongoing_elec] = (TSI0_DATA & TSI_DATA_TSICNT_MASK); // Save Counts for current electrode
u16temp_delta = gu16TSICount[ongoing_elec] - gu16Baseline[ongoing_elec]; // Obtains Counts Delta from callibration reference
if( u16temp_delta < 0)
gu16Delta[ongoing_elec] = 0;
else
gu16Delta[ongoing_elec] = u16temp_delta;
if(total_electrode > 1) //Change Electrode to Scan
{
if((total_electrode-1) > ongoing_elec) ongoing_elec++;
else ongoing_elec = 0;
TSI0_DATA = ((elec_array[ongoing_elec]<<TSI_DATA_TSICH_SHIFT) ); //选择接下来的通道
TSI0_DATA |= TSI_DATA_SWTS_MASK;
}
}
程序的要点是获取当前通道的转换值,并于参考值比较,得出变化值。
判断并选择LED状态:
void TSI_Slider_LED(void )
{
if(end_flag)
{
end_flag = FALSE;
if((gu16Delta[0] > gu16Threshold[0])||(gu16Delta[1] > gu16Threshold[1])||(gu16Delta[2] > gu16Threshold[2]))
{
if((gu16Delta[0] > gu16Threshold[0]))
{
GPIO_SET(MKL_PORTB,18);
GPIO_SET(MKL_PORTB,19);
GPIO_CLR(MKL_PORTD,1);
}
if((gu16Delta[1] > gu16Threshold[1]))
{
GPIO_SET(MKL_PORTB,18);
GPIO_CLR(MKL_PORTB,19);
GPIO_SET(MKL_PORTD,1);
}
if((gu16Delta[2] > gu16Threshold[2]))
{
GPIO_CLR(MKL_PORTB,18);
GPIO_SET(MKL_PORTB,19);
GPIO_SET(MKL_PORTD,1);
}
}else
{
SliderPercentegePosition[0] = NO_TOUCH;
SliderPercentegePosition[1] = NO_TOUCH;
SliderPercentegePosition[2] = NO_TOUCH;
SliderDistancePosition[0] = NO_TOUCH;
SliderDistancePosition[1] = NO_TOUCH;
SliderDistancePosition[2] = NO_TOUCH;
AbsolutePercentegePosition = NO_TOUCH;
AbsoluteDistancePosition = NO_TOUCH;
}
}
}
将预先设定的值与变换量比较,大于说明按键被按下,执行LED显示函数。
下面是视频:
源工程:
Touch.zip
(1.05 MB, 下载次数: 13)
|
评分
-
查看全部评分
|