zndz410 发表于 2014-5-13 11:46:20

【经验分享】 利用coldfire的ADC模块实现按键检测 (转)

    现在很多的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
** MCF52211ADC 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;
#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;
   }
}
}

FSL_TICS_ZJJ 发表于 2014-5-13 12:39:48

感谢楼主的资料分享,最好把工程或者文件以附件的形式放出来!

rockyyangyang 发表于 2014-9-5 16:08:42

感谢分享。            
页: [1]
查看完整版本: 【经验分享】 利用coldfire的ADC模块实现按键检测 (转)