原创 利用coldfire的ADC模块实现按键检测

2009-6-16 15:36 4799 4 4 分类: MCU/ 嵌入式

现在很多的MCU都集成了片上的KBI,即键盘按键中断,它很类似于8051单片机上的外部中断INT0,INT1,原理是简单的,当按键按下时,会有个下降沿用来触发中断。比如freescale公司的s08系列通常都会集成8路的KBI,用起来非常方便。


coldfire系列处理器有所谓的EPORT,这个片上模块可以很容易的实现KBI的功能。但常常在项目中,mcu的引脚资源很紧张,EPORT常与其他模块复用引脚,导致EPORT并不能总是用于KBI。在现在我们的这个项目中就是这样,采用mcf52211处理器,但是由于受限pcb板尺寸,我们用的LQFP64的处理器,其EPORT引脚只有3个,而我们的键盘却需要有6个按键,在这种情况下,我们采用mcf52211片上adc模块来实现按键检测。


coldfire系列的adc模块,其功能远远超出了一般的8位单片机和arm的功能,极其强大,下面贴出的代码思路很简单,就是利用coldfire片上adc的low limit compare功能,也就是当adc转换的结果低于指定的阈值(Low limit)时,将触发low limit compare中断,利用这个中断实现按键检测。






/******************************


** File: adc.h


** MCF52211 ADC module driver header file


*********************************/


#ifndef _LZP_MCF52211_ADC_H_
#define _LZP_MCF52211_ADC_H_
extern volatile uint16 g_adcStatus;
void init_adc(uint16 llimit0,uint16 llimit1);
void start_adc();
void stop_adc();


#endif





/*********************************


** File:adc.c


** MCF52211  ADC module driver


********************************/


#include "support_common.h" /* include peripheral declarations and more */
#include "adc.h"
#include "delay.h"


#define ALL_ADC          0xFF


/* Samples Enable SDIS Register */
#define ALL_ENABLED      0x00


/* Delay in the POWER Reg by reset */
#define DEFAULT_DELAY    0x00D0
volatile uint16 g_adcStatus;


/*******************
* set mcf52211's ADC module to loop sequential mode from SAMPLE0 to SAMPLE7
* set ADC interrupt enable
* set ADC Low Limit compare mode
********************/
void init_adc(uint16 llimit0,uint16 llimit1)
{
 uint8 i;
 
 g_adcStatus=0;
 MCF_GPIO_PANPAR =ALL_ADC;
 //set LOW limit interrupt enable
 MCF_ADC_CTRL1   = MCF_ADC_CTRL1_LLMTIE |MCF_ADC_CTRL1_SMODE(2); /* SMODE: This field controls the scan mode of the ADC module.
               For Loop sequential mode it has to be set 010 bin (2).  */ 
    MCF_ADC_CTRL2   = MCF_ADC_CTRL2_DIV(9);//set adc clock rate to 3MHZ
    /* The sampling order for channels */  /* ADLST1: contains an ordered list of the analog input channels to be
               converted when the next scan is initialized*/
    MCF_ADC_ADLST1 = MCF_ADC_ADLST1_SAMPLE0(0) |
          MCF_ADC_ADLST1_SAMPLE1(1) |
          MCF_ADC_ADLST1_SAMPLE2(2) |
          MCF_ADC_ADLST1_SAMPLE3(3);
    /* The sampling order for channels */
    MCF_ADC_ADLST2 = MCF_ADC_ADLST2_SAMPLE4(4) |
          MCF_ADC_ADLST2_SAMPLE5(5) |
          MCF_ADC_ADLST2_SAMPLE6(6) |
          MCF_ADC_ADLST2_SAMPLE7(7);
   /* set ADC interrupt*/
    MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK51 );
    MCF_INTC0_IMRL &=~( MCF_INTC_IMRL_MASKALL);
    MCF_INTC0_ICR51 =MCF_INTC_ICR_IP(7)+MCF_INTC_ICR_IL(2);
    /*set channel's low limit*/
    MCF_ADC_ADLLMT(0)=MCF_ADC_ADLLMT_LLMT(llimit0);
    MCF_ADC_ADLLMT(1)=MCF_ADC_ADLLMT_LLMT(llimit1);
    for(i=0;i<6;i++)
    {
     MCF_ADC_ADLLMT(i+2)=MCF_ADC_ADLLMT_LLMT(50);
    }
     /* All channels enabled */
    MCF_ADC_ADSDIS  = ALL_ENABLED;    /* ADSDIS: enables only the desired analog channels*/
    /* set the power-up delay in ADC */
    MCF_ADC_POWER   = DEFAULT_DELAY;   /* POWER: controls the power management of the ADC module*/
     /* wait until module is powered-up */
    while(MCF_ADC_POWER & MCF_ADC_POWER_PSTS0)  /* PSTS0 register: 0: ADC converter A is currently powered up,
               1: ADC converter A is currently powered down */
    ;           
    return;
}


/*
 * Start the ADC module
 *
 * Parameters: none
 *
 * Return : None.
 */
void start_adc()
{
 MCF_ADC_CTRL1 &= ~MCF_ADC_CTRL1_STOP0 ;
 MCF_ADC_CTRL1 |= MCF_ADC_CTRL1_START0;  /* CTRL1: is used to configure and control the ADC module.
               START0: A scan is started by writing a 1 to this bit.*/
 return;
}


//stop adc module
void stop_adc()
{
 MCF_ADC_CTRL1 |= MCF_ADC_CTRL1_STOP0 ;  /* CTRL1: is used to configure and control the ADC module.
               STOP0: A scan is stoped by writing a 1 to this bit.*/
 return;
}


//the adc isr
__declspec(interrupt:0) void adc_isr(void)
{
 uint16 prev_status,cur_status;
 if (MCF_ADC_ADSTAT & MCF_ADC_ADSTAT_LLMTI)
 {
  prev_status=MCF_ADC_ADLSTAT;
  MCF_ADC_ADLSTAT =0xffff;  //clear interrupt
  MCF_ADC_ADSTAT |= MCF_ADC_ADSTAT_EOSI0;
  MCF_ADC_CTRL1&=~MCF_ADC_CTRL1_LLMTIE;
  stop_adc();
  delay_ms(50);
  start_adc();
  //wait for adc conversion finish
  while((MCF_ADC_ADSTAT&MCF_ADC_ADSTAT_EOSI0)==0);
  MCF_ADC_ADSTAT |= MCF_ADC_ADSTAT_EOSI0;
  cur_status=MCF_ADC_ADLSTAT;
  if(cur_status==prev_status)
  {
   g_adcStatus=cur_status; 
  }
  else
  {
   g_adcStatus=0;
  }
  MCF_ADC_ADLSTAT =0xffff;  //clear interrupt
  MCF_ADC_CTRL1|=MCF_ADC_CTRL1_LLMTIE;
  
 }
}





/***********************************


** File :test.c


** test code for adc driver


** demo the keyboard break detect


** the keyboard is connect with mcf52211's AN2~AN7


************************************/


#include "support_common.h" /* include peripheral declarations and more */
//#if (CONSOLE_IO_SUPPORT || ENABLE_UART_SUPPORT)
/* Standard IO is only possible if Console or UART support is enabled. */
#include <stdio.h>
//#endif
#include "adc.h"
#include "uart0.h"
#define EnableInterrupts asm { move.w SR,D0; andi.l #0xF8FF,D0; move.w D0,SR;  }


int main(void)
{
 int counter = 0;
 unsigned char buf[30];
#if (CONSOLE_IO_SUPPORT || ENABLE_UART_SUPPORT)
 printf("Hello World in C from MCF52211 derivative on MCF52211 board\n\r");
 fflush(stdout);
#endif
 uart0_init(9600);
  init_adc(100,100);
  uart0_putstr((unsigned char*)("MCF52211 ADC test\n"));
  EnableInterrupts;


  start_adc();
 for(;;) {   
     counter++;
     if(g_adcStatus>0)
     {
      sprintf((char*)buf,"adc result: %d\n",g_adcStatus);
      uart0_putstr(buf);
      g_adcStatus=0;
     }
 }
}

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
4
关闭 站长推荐上一条 /3 下一条