这次用mspm0l1306实现的小项目需要用到输入捕获,前面2个帖子也把定时器的其它功能进行了测试,也算是把定时器的功能都试了一遍。TI的定时器还是易用的,包括CCS的初始化功能,还有清晰的函数名,都能帮助用户快速上手。
在本例中使用输入捕获的目的是测量输入信号的频率。因此使用输入捕获需要用到2个中断:load中断和捕获中断。通过2次捕获之间的时间差,得到信号的频率。
捕获使用的是TIMG1,设置的定时器周期为2S,初始化如下图所示:
中断使用通道0的捕获和定时器的load中断
在load负载中记录load的次数,在捕获时记录当前CCR的值,通过下面这个函数获得CCR的值。
DL_Timer_getCaptureCompareValue(CAPTURE_0_INST,DL_TIMER_CC_0_INDEX);
通过将每次捕获的时间放入环形数组中,然后在后台的while循环中读取最近两次的计数值得到时间差,从而计算信号的频率。
代码见下方
中断函数
typedef struct {
uint32_t period;
uint32_t ccr;
}TimestampStruct;
typedef struct{
TimestampStruct time[20];
uint8_t write_index;
uint32_t count;
}TimestampBufStruct;
TimestampBufStruct timestamp_buf;
void CAPTURE_0_INST_IRQHandler()
{
TimestampStruct nowtime;
static uint32_t period_count;
switch(DL_TimerG_getPendingInterrupt(CAPTURE_0_INST)){
case DL_TIMER_IIDX_CC0_DN:
nowtime.period = period_count;
nowtime.ccr = DL_Timer_getCaptureCompareValue(CAPTURE_0_INST,DL_TIMER_CC_0_INDEX);
write_new_timestamp(nowtime);
DL_GPIO_togglePins(USER_PORT,USER_R_LED_PIN);
break;
case DL_TIMER_IIDX_LOAD:
period_count++;
DL_GPIO_togglePins(USER_PORT,USER_R_LED_PIN);
break;
default:
break;
}
}
时间戳写入环形数组的代码
void write_new_timestamp(TimestampStruct timestamp)
{
timestamp_buf.time[timestamp_buf.write_index] = timestamp;
timestamp_buf.count++;
timestamp_buf.write_index++;
if(timestamp_buf.write_index >= 20){
timestamp_buf.write_index = 0;
}
}
计算频率的代码
uint32_t get_timestamp_diff()
{
uint8_t index = timestamp_buf.write_index;
TimestampStruct nowtime,lasttime;
char str1[50];
uint32_t time_dif = 0;
if(index > 0){
nowtime = timestamp_buf.time[index-1];
}else{
nowtime = timestamp_buf.time[19];
}
if((index -1) > 0){
lasttime = timestamp_buf.time[index-2];
}else{
lasttime = timestamp_buf.time[19];
}
if(nowtime.period == lasttime.period){
time_dif = lasttime.ccr- nowtime.ccr;
}else if(nowtime.period -lasttime.period == 1){
nowtime.ccr = 40000-nowtime.ccr;
lasttime.ccr = 40000-lasttime.ccr;
time_dif = 40000 - lasttime.ccr + lasttime.ccr;
}else{
time_dif = (nowtime.period - lasttime.period -1)*40000;
time_dif += 40000 - lasttime.ccr + lasttime.ccr;
}
return time_dif;
}
float compute_freq()
{
uint32_t diff;
float freq;
if(timestamp_buf.count >= 2){
diff = get_timestamp_diff();
if(diff != 0){
freq = 20000.0 /diff;
return freq;
}else{
return 0;
}
}else{
return 0;
}
}
主函数
char str[100] ="helo";
float frq;
int i_frq;
int main(void)
{
SYSCFG_DL_init();
// APP_DL_UART_0_init();
NVIC_EnableIRQ(CAPTURE_0_INST_INT_IRQN);
send_multi_data_by_uart((uint8_t*)str,strlen(str));
DL_TimerG_startCounter(CAPTURE_0_INST);
while (1) {
delay_cycles(32000000);
frq = compute_freq();
i_frq = (int)frq;
snprintf(str,50,"freq:%d\r\n",i_frq);
send_multi_data_by_uart((uint8_t*)str,strlen(str));
}
}
计算的频率还是比较准的,用示波器输出了1khz的信号,采集到的频率也是1khz。
最后要补充的是,编译器好像不支持浮点数,用想用sprintf函数输出浮点数的值时,会进入硬件错误的死循环中,所以代码改成了输出整型数据。