合泰触控芯片开发

本次公司项目,需要用到合泰的触控芯片BS82D20A-3,是一款8位,有20个触控引脚的国产芯片。芯片提供商给了相关的触控程序软件包。软件包版本V101。

开发过程

 1.硬件

    本身只是一个简单的墙板触控PCB,所以硬件及其简单,需要考虑的就是不要将芯片放在触控面后,走线尽量避开触控面。本身只需要有几个简单的功能,UART、TS和e-link的调试(晶振、复位芯片自身都有)。


2.软件

    2.1 关于相关外设的调试

        肯定不可能一开始就作触控,先调试相关的UART和定时器。当然还有最最重要的时钟,这些都可以通过看手册来编写

/*--------------------------看门狗寄存器设置----------------------------------*/

_wdtc = 0b01010111;
//b7~b3:01010使能
//b2~b0:溢出周期选择位 011:2的18次方/32K低速时钟 则为8s

_clrwdt(); //喂狗

/*-------------------------系统时钟寄存器设置---------------------------------*/
// _smod = (_smod&0x40)|0x01;
//b7~b5:系统时钟选择位
//b4:空
//b3:低速振荡器就绪标志位
//b2:高速振荡器就绪标志位
//b1:空闲模式控制位 
//b0:系统时钟选择位 0分频时钟/低速时钟  1全速时钟
_hlclk = 1;
_idlen = 0;

// _ctrl = (_ctrl&0x47)|0x00;
//bit7:空闲模式下的系统时钟控制
//bit6:未使用
//bit5~4:高频时钟选择位,8Mhz
//bit3:低功耗控制,0快速启动
//bit2:有效低电压复位标志
//bit1:无
//bit0:设置WE[4:0]引起的复位
_fsyson = 0;
_hircs0 = 1;
_hircs1 = 1;
_lxtlp = 0;

_clrwdt();

/*---------------------------------中断寄存器设置------------------------------------*/


/*--------------------------------串口功能初始化-------------------------------------*/

_ucr1 = (_ucr1&0x13)|0x80; //UART功能的第一个控制寄存器
//bit7:UARTEN,UART功能使能位
//bit6:BN0,发送数据选择位
//bit5:PREN,奇偶校验使能位
//bit4:PRT,奇偶校验选择位
//bit3:STOPS,停止位的长度选择
//bit2:TXBRK:暂停字发送控制位
//bit1:RX8:接收9-bit数据传输格式中的第8位(只读)
//bit0:TX8:发送9-bit数据传输格式中的第8位(只写)

_ucr2 = 0b11000000; //UART功能的第二个控制寄存器
//bit7:TXEN,UART发送数据使能位
//bit6:RXEN,UART接收数据使能位
//bit5:BRGH,波特率发生器高低速选择位
//bit4:ADDEN,地址检测使能位
//bit3:WAKE,RX脚下降沿唤醒功能使能位
//bit2:RIE:接收中断使能位
//bit1:TIIE:发送器空闲中断使能位
//bit0:TEIE:发送寄存器位空中断使能位

// _brg = _brg&0x0c; //波特率控制寄存器 (波特率位9600)
_brg3 = 1;
_brg2 = 1;


/*------------------------------------IO口功能初始化------------------------------------*/
// _pac = (_pac&0x77)|0x08;
_pac7 = 0;
_pac3 = 1;
_pac1 = 0;
//bit7:PA7为UART_TX设置为输出0
//bit6:无
//bit5:无
//bit4:PA4没用到
//bit3:PA3为UART_RX设置为输入1
//bit2:PA2为ICPCK
//bit1:PA1没用到
//bit0:PA0为ICPDA


// _papu = (_papu&0x7f)|0x80; //PA7设置为上拉,推挽输出
_papu7 = 1;
_papu1 = 1;
_pawu = (_pawu&0x60)|0x00; //PAWU寄存器是使能低功耗,没有使用,全除能,为0x00

// _pa = (_pa&0x72)|0x8d; //此次没有用到PA1和PA4,置高PA7,PA3,PA2,PA0
_pa7 = 1;
_pa3 = 1;


_pa1 = 1;



//  _pdc = (_pdc&0xf0)|0x0c; //PD2,PD3输入接收触控信号,PD0输出BUZZER信号,PD1输出LED信号
// _pdpu = (_pdpu&0xf0)|0x03; //PD0,PD1推挽输出
  _pdc1 = 0;
  _pdc0 = 0;
_pdpu1 = 1;
_pdpu0 = 1;
  _pd = (_pd&0xf0)|0x03; //LED亮,BUEEZR

_sledc0 = 0b00001111;
//源电流选择位( 引脚为CMOS 输出时,相应源电流选择位的设置才有效 )
//b7~b6:PB7~PB4电流选择位
//b5~b4:PB3~PB0电流选择位
//b3~b2:PA7和PA4电流选择位
//b1~b0:PA3~PA0电流选择位


_sledc1 = 0b00110000;
//源电流选择位( 引脚为CMOS 输出时,相应源电流选择位的设置才有效 )
//b7~b2:空
//b1~b0:PD3~PD0电流选择位

_clrwdt(); //喂狗


以上是我在USER_PROGRAM_INITIAL()中写的寄存器设置的初始化,再写程序的时候一定要记得喂狗!!!

接下来就是初始化一个定时器,用来做系统计时,我选择了CTM0 CCRA,这款芯片的定时中断产生条件是比较匹配,当计数器寄存器的值和预先设置的_ctm0al、_ctm0ah比较,匹配成功发生中断。

/*--------------------------TMPC寄存器设置-------------------------*/
_tmpc = (_tmpc&0xf0)|0x00; //因为使用CTM0的定时/计数器模式,所以CTM0的输出控制脚必须除能


/*-----------------------CTM0C0寄存器的设置------------------------*/
_ct0pau = 0; //CTM0计数器暂停控制位,0:运行,1:暂停

_ct0ck2 = 0; //000:fSYS/4,001:fSYS,010:fH/16,011:fH/64,100:fSUB,101:fSUB,110:TCK0 上升沿时钟,111:TCK0 下降沿时钟
_ct0ck1 = 1; //选择011,fH/64,fH已经选择为8MHz
_ct0ck0 = 0; //定时器频率为500KHz

_ct0on = 0; //CTM0 计数器On/Off 控制位,先关,设置好CTM0工作模式后再开启

//使用CTM0 CCRA寄存器,不需要设置CCRP的值,bit2~0空闲


/*-----------------------CTM0C1寄存器的设置-----------------------*/
_ct0m1 = 1; //00:比较匹配输出模式,01:未定义,10:PWM 模式,11:定时/计数器模式
_ct0m0 = 1; //定时计/数器模式

//本次使用定时计/数器模式,未使用CT0IO1和CT0IO0寄存器
//本次使用定时计/数器模式,未使用CT0OC寄存器
//本次使用定时计/数器模式,未使用CT0POL寄存器
//本次使用定时计/数器模式,未使用CT0DPX寄存器

_ct0cclr = 1; //0:CTM0比较器P匹配,1:CTM0比较器A匹配

/*-----------------------CTM0AL和CTM0AH寄存器---------------------*/

_ctm0al = _ctm0al|0xff;
_ctm0ah = _ctm0ah|0x03; //2ms一次中断

/*-----------------------开定时器中断寄存器-----------------------*/

_emi = 1; //开总中断
_ctma0e = 1; //CTM0 CCRA比较器中断控制位使能
_ctma0f = 0; //CTM0 CCRA比较器中断请求标志位清零

_ct0on = 1; //CTM0 计数器On/Off 控制位,再开


void __attribute((interrupt(0x14))) Interrupt_CTM0_CCRA(void)
{

_ctma0f = 0 ; //中断标志位清零
Sysclk ++; //最终值*2,单位ms就是系统运行时间
}

以上一定要记得要使用CCRA一定要除能TP0,TP1,折磨了我至少2小时的这个东西,看手册不仔细,没有注意到这个。


接下来就是UART,非常简单,只是用来调试相关的触控按键,接下来的额复杂的就不能放出来了,涉及到公司相关的编码协议。

/*********************************UART发送缓冲区(发送单个字节)**************************************/
void UART_SendByte(uchar Send_Data)
{
_clrwdt(); //喂狗

_usr;
_txr_rxr; //清除FREE帧错误标志位

  if((Send_Data != '\0')&TI)
  {
_usr; //读取usr寄存器
SBUF = Send_Data; //数据写入TXR寄存器,清除了TXIF标志位
  }
 
  while(!TD) //TD为数据发送完成标志位
{
continue;
}

}


/***********************************UART接收缓冲区(接收单个字节)*************************************/
uchar UART_RecByte(void)
{
uchar data = 0;

_clrwdt(); //喂狗

_usr;
_txr_rxr; //清除FREE帧错误标志位

if(!_rxif)
{
_usr;
    data = SBUF;
}

return(data);

}


需要注意的是:合泰的单片机的发送标志位TI也就是_txif不是手动置1,具体看程序或者数据手册。

2.2    最重要的,也是最简单的(但是我花了2天,调出来之后骂了自己一句sb)

        触控的调试,其实相关软件包已经帮你把所有的事情做完了,只需要调用函数就行了,这里不只要吐槽我自己,还要吐槽一下写芯片用户手册和软件包使用手册的大佬,“能不能多写两个字啊,别人STM32动不动800页,1000页,你就200多,还有的不说清楚”。

        一开始调用软件包,调试的时候发现根本没起来,先读手册上的标志位寄存器,再读软件包的标志位变量,全部表示没起来,这就很纳闷了。后来发现,什么初始化,根本不需要,如果一步步看一下那个汇编初始化就会发现,触控的初始化早就帮你做完了。你只需要再循环中调用BS82D20A_LIBV413();按键就能起来。

while(1)
{
_clrwdt(); //喂狗

BS82D20A_LIBV413();

GET_KEY_BITMAP(); //得到按键数据

TKS_state.key_state1 = DATA_BUF[0];
TKS_state.key_state2 = DATA_BUF[1];
TKS_state.key_state3 = DATA_BUF[2];


if( Process_TKS_State() > 0 )
{
Process_TKS();
}

}


以上就是USER_PROGRAM中具体的循环。其中的一些触控处理函数忽略就好了(我用到了18个按键,所以读DATA_BUF三次)。

其实中间一天发现软件包用不起来之后还写了一个直接操作寄存器的方案,结果大家都猜到了(卒)。

这里又说到了吐槽,写直接操作寄存器方案的时候看到手册触控这章节中反复提到5位时隙计数器,16位C/F振荡器,16位时隙计数器,8位时隙计数器。其中8位我清楚,但是5位呢?我根本没找到啊!,而且每次介绍都是16计数器寄存器,我咋知道你那个是16位C/F振荡器,那个是真的16位时隙计数器。最后直接放弃,幸好回头调出来了。