觸摸控制芯片MPR121驅動移植(STM32)

  • 本文記錄將arduino下的mpr121觸摸板驅動程序移植到stam32f1

1、觸摸板簡介

之前買了塊mpr121做主控的觸摸控制板(如下圖),賣家給的驅動是arduino的,最近做項目需要移植到stm32上。看了mpr121的用戶指南和arduino的程序,其實要移植要做的工作也不是特別多,主要就是iic和外部中斷。
mpr121觸摸板

2、移植思路

mpr121採用中斷方式與MCU通信,協議用的是IIC。移植要做的就是做好stm32的iic和外部中斷初始化,然後按照mpr121的通信要求封裝IIC的幾個基本函數就行了,步驟整理如下。
1、stm32下的外部中斷配置和IIC通信配置
2、按照用戶手冊的要求封裝基本的IIC函數
3、移植初始化函數和按鍵讀取函數

3、移植

3.1、stm32的IIC和外部中斷配置

這裏問我直接用的正點原子的模擬IIC例程和野火的外部中斷例程。外部中斷初始化後就是中斷服務函數的編寫,這個放在後面按鍵讀取函數那說明。IIC使用模擬的,這個點原子的例程裏提供了幾個基本的通信函數。

//IIC所有操作函數
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//發送IIC開始信號
void IIC_Stop(void);	  			//發送IIC停止信號
void IIC_Send_Byte(u8 txd);			//IIC發送一個字節
u8 IIC_Read_Byte(unsigned char ack);//IIC讀取一個字節
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信號
void IIC_Ack(void);					//IIC發送ACK信號
void IIC_NAck(void);				//IIC不發送ACK信號

其中IIC_Read_Byte(unsigned char ack)這個函數的說明如下

//讀1個字節,ack=1時,發送ACK,ack=0,發送nACK   
u8 IIC_Read_Byte(unsigned char ack)

3.2、IIC通信函數的封裝

賣家給的例程裏跟mpr121通信的函數有兩個,一個是 unsigned char mpr121Read(uint8_t address)另一個是void mpr121Write(unsigned char address, unsigned char data)(這裏原本的程序讀取是分成兩步的,我把它合併成一步了)。我們只要按照mpr121的通信要求實現這兩個函數就行。

這裏我對stm32的iic通信函數又做了一次封裝爲的是少打代碼(笑),如下:

/*********************
 ****I2C Functions****
 *********************/ 

void i2cInit(void)   //iic引腳初始化
{ 
	IIC_Init();
}


void i2cSendStart(void)  // 發送起始信號
{  
	IIC_Start();

}

void i2cSendStop(void)   //發送終止信號
{    
	// transmit stop condition
       IIC_Stop();
}

void i2cWaitForComplete(void)   //等待應答信號
{
	IIC_Wait_Ack();
} 

void i2cSendByte(unsigned char data)  //發送一個字節
{ 
	IIC_Send_Byte(data);
}

unsigned char i2cReceiveByte(unsigned char ackFlag)   //接收一個字節,ackFlag=1:應答,ackFlag=0:不應答
{
	return IIC_Read_Byte(ackFlag);
}

·發送函數

mpr121用戶手冊中接收數據的時序要求如下圖
mpr121接收

例程中使用的是上圖第二個通信時序,我們照搬就成,程序實現如下



void mpr121Write(unsigned char address, unsigned char data)
{
  i2cSendStart();
  
  i2cSendByte(MPR121_W);// write 0xB4
  i2cWaitForComplete();
  
  i2cSendByte(address);	// write register address
  i2cWaitForComplete();
  
  i2cSendByte(data);
  i2cWaitForComplete();
  
  i2cSendStop();

}
  • 讀取函數
    mpr121用戶手冊中對讀取的時序要求如下
    讀mpr121
    函數實現如下
unsigned char mpr121Read(uint8_t address)
{
  unsigned char  data;
  
  i2cSendStart();
 
  
  i2cSendByte(MPR121_W);	// write 0xB4
  i2cWaitForComplete();
  
  i2cSendByte(address);	// write register address
  i2cWaitForComplete();
  
  i2cSendStart();
  
  i2cSendByte(MPR121_R);	// write 0xB5
  i2cWaitForComplete();
  data =i2cReceiveByte(TRUE);
  
  
  i2cSendStop();
  
  return data;
}

其中有關地址的說明如下,設備地址左移一位,最低位爲1或0表示讀或者寫(具體參考mpr121數據手冊)


#define MPR121_R 0xB5	// ADD pin is grounded
#define MPR121_W 0xB4	// So address is 0x5A

3.3、 移植初始化函數和按鍵讀取函數

實現了與mpr121通信之後就是對mpr121的初始化了,這裏我直接用的例程中的初始化序列,如果是後期自己做touchpad的話還得自己去看數據手冊並且更改相應的參數,這裏就不深入探討了。

  • 初始化序列如下(外部中斷的初始化也放在了這裏)
void mpr121QuickConfig(void)
{
	
	 mpr121_irqInit();//interrupt set
  // Section A
  // This group controls filtering when data is > baseline.
  mpr121Write(MHD_R, 0x01);
  mpr121Write(NHD_R, 0x01);
  mpr121Write(NCL_R, 0x00);
  mpr121Write(FDL_R, 0x00);

  // Section B
  // This group controls filtering when data is < baseline.
  mpr121Write(MHD_F, 0x01);
  mpr121Write(NHD_F, 0x01);
  mpr121Write(NCL_F, 0xFF);
  mpr121Write(FDL_F, 0x02);
  
  // Section C
  // This group sets touch and release thresholds for each electrode
  mpr121Write(ELE0_T, TOU_THRESH);
  mpr121Write(ELE0_R, REL_THRESH);
  mpr121Write(ELE1_T, TOU_THRESH);
  mpr121Write(ELE1_R, REL_THRESH);
  mpr121Write(ELE2_T, TOU_THRESH);
  mpr121Write(ELE2_R, REL_THRESH);
  mpr121Write(ELE3_T, TOU_THRESH);
  mpr121Write(ELE3_R, REL_THRESH);
  mpr121Write(ELE4_T, TOU_THRESH);
  mpr121Write(ELE4_R, REL_THRESH);
  mpr121Write(ELE5_T, TOU_THRESH);
  mpr121Write(ELE5_R, REL_THRESH);
  mpr121Write(ELE6_T, TOU_THRESH);
  mpr121Write(ELE6_R, REL_THRESH);
  mpr121Write(ELE7_T, TOU_THRESH);
  mpr121Write(ELE7_R, REL_THRESH);
  mpr121Write(ELE8_T, TOU_THRESH);
  mpr121Write(ELE8_R, REL_THRESH);
  mpr121Write(ELE9_T, TOU_THRESH);
  mpr121Write(ELE9_R, REL_THRESH);
  mpr121Write(ELE10_T, TOU_THRESH);
  mpr121Write(ELE10_R, REL_THRESH);
  mpr121Write(ELE11_T, TOU_THRESH);
  mpr121Write(ELE11_R, REL_THRESH);
  
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  mpr121Write(FIL_CFG, 0x04);
  
  // Section E
  // Electrode Configuration
  // Enable 6 Electrodes and set to run mode
  // Set ELE_CFG to 0x00 to return to standby mode
  mpr121Write(ELE_CFG, 0x0C);	// Enables all 12 Electrodes
  //mpr121Write(ELE_CFG, 0x06);		// Enable first 6 electrodes
  
  // Section F
  // Enable Auto Config and auto Reconfig
  /*mpr121Write(ATO_CFG0, 0x0B);
  mpr121Write(ATO_CFGU, 0xC9);	// USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   mpr121Write(ATO_CFGL, 0x82);	// LSL = 0.65*USL = 0x82 @3.3V
  mpr121Write(ATO_CFGT, 0xB5);*/	// Target = 0.9*USL = 0xB5 @3.3V

}

然後就是按鍵讀取了,這裏的思路是在外部中斷的中斷服務程序中將按鍵標誌置位,然後在主程序中檢測到標誌置位後再讀取鍵值,當然也可以在中斷服務程序中就完成這些工作。代碼如下

  • 中斷服務程序
void KEY1_IRQHandler(void)
{
  //確保是否產生了EXTI Line中斷
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) 
	{
		key_pressed=0;
		LED0=!LED0;
    //清除中斷標誌位
		EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
	}  
}
  • 鍵值讀取
char getPhoneNumber()
{
  int touchNumber;
	int j;
  uint16_t touchstatus;
	char key=-1;
  //Serial.println("Please Enter a phone number...");
  
    //while(key_pressed);//用while讀取會阻塞程序運行
	if(key_pressed==0)//非阻塞方式
	{
	key_pressed=1;
    touchNumber = 0;
    
    touchstatus = mpr121Read(0x01) << 8;
    touchstatus |= mpr121Read(0x00);
    
    for (j=0; j<12; j++)  // Check how many electrodes were pressed
    {
      if ((touchstatus & (1<<j)))
        touchNumber++;
    }
    
    if (touchNumber == 1)
    {
      if (touchstatus & (1<<STAR))
        key = '*';
      else if (touchstatus & (1<<SEVEN))
        key = '7';
      else if (touchstatus & (1<<FOUR))
        key= '4';
      else if (touchstatus & (1<<ONE))
        key = '1';
      else if (touchstatus & (1<<ZERO))
        key= '0';
      else if (touchstatus & (1<<EIGHT))
        key = '8';
      else if (touchstatus & (1<<FIVE))
        key = '5';
      else if (touchstatus & (1<<TWO))
        key = '2';
      else if (touchstatus & (1<<POUND))
        key = '#';
      else if (touchstatus & (1<<NINE))
        key = '9';
      else if (touchstatus & (1<<SIX))
        key = '6';
      else if (touchstatus & (1<<THREE))
        key = '3';
        
      //Serial.print(key[i]);
      
    }
    else if (touchNumber == 0);
    else;
      //Serial.println("Only touch ONE button!");
	}
		return key;
}

到這裏mpr121觸控板的驅動程序就移植完成了,下面給出完整的工程文件
文章不足之處歡迎提出建議。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章