本帖最后由 qjp1988113 于 2020-10-20 13:35 编辑
下面开始调试AC781X开发板。官方提供的例程均未从最简单的单一外设着手,而是一些
小型的几个外设的复合的程序,添加了些趣味性。
其中GPIO里面的一个多路按键的例子很有意思,思路很不错。
硬件电路设计如下:
可以看出,按下不同的按键,ADC检测的电压值不一样,这样我们就可以区分是哪一个按键按下了。
在IO管脚紧张,而ADC通道又有剩余的情况下,是个不错的选择。官方的例程,文档啥的,其实做的还是不错的。
这个调试GPIO不同模式的例子。每种模式都写了个相应的c文件,然后通过不同的宏定义,来执行对应函数。
例程中的中文注释的很详细:
下面为gpio_mux.c文件:
/*************<include>****************/
#include "gpio.h"
#include "ac78xx_timer.h"
#include "ac78xx_adc.h"
#if (GPIO_SAMPLE_SEL == GPIO_MUX_SAMPLE)
/*************<macro>******************/
/*************<enum>*******************/
/*************<union>******************/
/*************<struct>*****************/
/*************<variable>***************/
uint8_t g_scanKeyTimeCnt = 0;
uint32_t g_getSampKeyVal = 0;
uint8_t g_getK3CurtSts = 0,g_getK4CurtSts = 0,g_getK5CurtSts = 0;
/*************<prototype>**************/
void TIM2_IRQnCallBack(uint8_t lparam);
/**
* @prototype GPIO_Mux_Sample(void)
*
* @param[in] void
* @return void
*
* @brief Judge action of the keys by GPIO and achieve LED toggle.
* 通过GPIO识别按键动作,完成LED状态翻转.
*/
void GPIO_Mux_Sample(void)
{
GPIO_InitHardwr();
ADC_InitHardwr();
TIMER_InitHardwr();
while(1)
{
GPIO_ScanKeyAction();
}
}
/**
* @prototype GPIO_InitHardwr(void)
*
* @param[in] void
* @return void
*
* @brief Initalize GPIO module.
* 初始化GPIO模块.
*/
void GPIO_InitHardwr(void)
{
GPIO_SetDir(LED2_PIN, GPIO_OUTPUT);//设置LED引脚为输出
GPIO_SetDir(LED3_PIN, GPIO_OUTPUT);
LED2_ON;//默认上电都点亮
LED3_ON;
}
/**
* @prototype GPIO_ScanKeyAction(void)
*
* @param[in] void
* @return void
*
* @brief Scan Key Action Priodly.
* 扫描按键动作.
*/
void GPIO_ScanKeyAction(void)
{
if (g_scanKeyTimeCnt > 9)//每10ms扫描一次按键
{
g_scanKeyTimeCnt = 0;
g_getSampKeyVal = ADC_GetSampKeyVal();//获取ADC采样结果
/*这里之所以需要记住按键状态,目的是准确识别用按键动作,避免按键一次,执行动作多次*/
if ((g_getK5CurtSts == KEY_UNDOWN) && (g_getSampKeyVal < 900))//(4095 * (560 / 2560))),K5按下,只有K5按下后松开,记为一次按键动作
{
LED2_OFF;
LED3_OFF;
g_getK5CurtSts = KEY_DOWN;//记住按键按下状态
}
else if ((g_getK4CurtSts == KEY_UNDOWN) && (g_getSampKeyVal < 2100) && (g_getSampKeyVal > 900))//(4095 * (2060 / 4060)))
{
LED3_TOGGLE;
g_getK4CurtSts = KEY_DOWN;//记住按键按下状态
}
else if ((g_getK3CurtSts == KEY_UNDOWN) && (g_getSampKeyVal < 3200) && (g_getSampKeyVal > 2100))//(4095 * (6760 / 8760)))
{
LED2_TOGGLE;
g_getK3CurtSts = KEY_DOWN;//记住按键按下状态
}
else if (g_getSampKeyVal == 4095)//按键松开
{
g_getK3CurtSts = KEY_UNDOWN;//恢复按键状态为未按下状态
g_getK4CurtSts = KEY_UNDOWN;
g_getK5CurtSts = KEY_UNDOWN;
}
}
}
/**
* @prototype TIMR_InitHardwr(void)
*
* @param[in] void
* @return void
*
* @brief Initalize TIM2 module.
* 初始化TIM2模块.
*/
void TIMER_InitHardwr(void)
{
TIMER_ConfigType timerConfig = {0};
timerConfig.loadValue = (48000000 / (1000 - 1));//定时器时钟只能是外设总线时钟
timerConfig.linkMode = 0;//不使用多定时器进行链接
timerConfig.interruptEn = 1;//使能中断
timerConfig.timerEn = 1;//使能定时器
TIMER_SetCallback(TIMER2,TIM2_IRQnCallBack);//设置中断回调函数
TIMER_Init(TIMER2,&timerConfig);
}
/**
* @prototype TIM2_IRQnCallBack(uint8_t lparam)
*
* @param[in] ...
* @return ...
*
* @brief TIM2 module interrupt handler.
* TIM2中断处理函数.
*/
void TIM2_IRQnCallBack(uint8_t lparam)
{
if (TIMER_GetIntFlag(TIMER2))
{
TIMER_ClrIntFlag(TIMER2);
if (g_scanKeyTimeCnt < 0xFF)
{
g_scanKeyTimeCnt++;
}
}
}
/**
* @prototype ADC_InitHardwr(void)
*
* @param[in] void
* @return void
*
* @brief Initialize ADC module and corresponding pin.
* 初始化ADC模块以及对应引脚.
*/
void ADC_InitHardwr(void)
{
ADC_InitType adcConfig = {0};
ADC_TrigSourceType adcTrigSrc = {0};
GPIO_SetFunc(K3_4_5_PIN, GPIO_FUNC_1);//设置引脚复用,复用功能1,ADC_IN1
adcConfig.dataAlign = ADC_DataAlign_Right;//数据右对齐
adcConfig.scanMode = ADC_Regular_Single_One_Mode;//一次只转换一个通道
ADC_Init(ADC, &adcConfig);
adcTrigSrc.regularTrigSource = ADC_TrigSource_Internal;//选择内部触发
ADC_SetClockPrescaler(ADC, ADC_ADIV_DIVIDE_8);//设置分频系数,48M/8=6Mhz
ADC_TrigSourceInit(ADC, &adcTrigSrc);
ADC_SetRegularGroupLength(ADC, 1);//规则组,通道总数只有1个
ADC_SetRegularGroupSequence(ADC, 1, ADC_CHANNEL_AD1);//选择转换通道
ADC_ChannelSampleTimeSel(ADC, ADC_CHANNEL_AD1, ADC_SampleTime_14Cycle);//设置通道采样时间
ADC_Cmd(ADC, ENABLE);
}
/**
* @prototype ADC_GetSampKeyVal(void)
*
* @param[in] void
* @return Sample AD value of the key3/4/5 voltage.
*
* @brief Sample key pin voltage.
* 采样按键引脚电压.
*/
uint32_t ADC_GetSampKeyVal(void)
{
ADC_SoftwareStartRegularConvCmd(ADC, ENABLE);//软件触发转换
while(!ADC_GetIntFlag(ADC, ADC_FLAG_EOC));//等待转换完成
return (ADC_GetRegularConversionValue(ADC));//获取结果
}
#endif
/*************<end>********************/
程序很简单,还是传统的定义结构体的写法,各种参数定义在结构体里面。只需配置流程正确,一般很难出错。
这里面GPIO,TIMER.ADC都写在一个文件里面了,如果独立分开,那么感觉结构就更清晰了。
程序如何运作的,文件里面标注的中文注释解释的已经很清楚了。这里给杰发赞一个,全篇中文注释。都国产了,还不发挥本土的语言优势?
虽然才调了第二个例子,芯片的参考手册也还没看,但我觉得上手应该很容易。
本例子中:TIMER做延时,while大循环里面,每隔10ms检测一次ADC采样通道引脚电压有无变化,
如果有变化,判断采样值在什么范围,来确定哪一个引脚,然后再触发相应引脚对应的任务。
IO引脚控制用了位段(Bit bond)控制的操作方式,使程序看起来简洁多了。
调试下载,现象如下:
|