提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:本次使用ATTINY1616-SNR作为核心控制器,裸片测试
近期需要使用AT系列的一款单片机,用与特定频率信号的测量记录一下上手这款单片机的一个过程,主要使用了该单片机的串口功能、PWM波生成功能、定时器模块、事件管理系统以及实时定时器。
主流程为:使用pwm生成模块生成固定频率的方波,接入芯片的事件触发引脚,触发对应的事件中断,记录对应的定时器的计数值,利用计数器的记录值结合系统主频反推出信号的频率,在RTC模块中设置1s的定时器,通过串口将所测得的频率信息打印出来。
工程文件与芯片手册资源
提示:以下是本篇文章正文内容,思路仅供参考,有不足之处还望大家匹配指正
一、开发环境
使用Atmel公司的Microchip Studio作为本次的开发环境,芯片ATTINY1616-SNR,仿真器Atmel-ICE。
二、初始化
1.图形化初始化
图形化初始化网站
点击create创建一个新的工程
选择对应的型号,并选择对应的外设,本次使用到PWM1、Event System1、RTC1、Usart1、Timer*1配置完成之后点击右下角Create
整个工程框架如下图所示
主时钟树如下图所示
配置波形生成模块作为本次测量频率的输入
生成波形的输出频率≈主时钟频率/(Value_Top)由引脚PB0输出–(本次主频20M按上图所配置的频率约为20KHz 占空比约50%)
对输入捕获定时器功能进行配置,选用其频率测量功能
事件系统的配置,首先需要配置对应的引脚
内部链接
配置串口
配置实时时钟产生1s的定时中断,用于串口数据的打印
开启全局使能
配置完成之后点击Export Project生成所配置的工程
至此完成所有功能的配置
2.功能实现
中断服务函数application_isr.c:
/*
* application_isr.c
*
* Created: 2022-04-07 17:00:23
* Author: dell
*/
#include <atmel_start.h>
#include "application_isr.h"
extern uint8_t rtcFlag;
extern uint32_t periodSum;
extern uint32_t pulseWidthSum;
extern uint8_t samplescount;
/**
* **********************************************************
* ISR
For every one second RTC interrupt is generated
* **********************************************************
**/
ISR(RTC_PIT_vect)
{
/* Insert your PIT interrupt handling code here */
rtcFlag = 1;
/* The interrupt flag has to be cleared manually */
RTC.PITINTFLAGS = RTC_PI_bm;
}
/**
* *********************************************************************************
* ISR
Capture Interrupt is generated for every one period measurement of the signal
* *********************************************************************************
**/
ISR(TCB0_INT_vect)
{
if (samplescount < MAXSAMPLES_COUNT) {
pulseWidthSum += TCB0.CCMP;
periodSum += TCB0.CNT;
samplescount = samplescount + 1;
} else {
// no operation
}
TCB0.INTFLAGS = TCB_CAPT_bm;
}
该函数中用于处理中断所产生的请求以及计数器值的捕获。
应用功能函数application.c
/*
* application.c
*
* Created: 2022-04-07 16:57:22
* Author: Zxy
*/
/**
* **********************************************************
* Macros definitions
* **********************************************************
**/
#include <atmel_start.h>
#include <stdio.h>
#include "application.h"
#define F_CPU 20000000
volatile uint8_t rtcFlag;
volatile uint8_t samplescount = 0;
volatile uint32_t periodAfterCapture = 0;
volatile uint32_t pulseWidthAfterCapture = 0;
volatile uint32_t periodAfterCaptureAvg = 0;
volatile uint32_t pulseWidthAfterCaptureAvg = 0;
volatile uint32_t periodSum = 0;
volatile uint32_t pulseWidthSum = 0;
volatile uint32_t captureDuty = 0;
volatile uint32_t captureFrequency = 0;
uint8_t buffer[60];
/**
@Param
none
@Returns
none
@Description
function to transmit a data on terminal window
**/
void SendString(const char *data)
{
uint8_t i = 0;
for (i = 0; data[i] != '\0'; i++) {
// sending the data through EUSART2 peripheral
USART_0_write(data[i]);
}
}
/**
@Param
none
@Returns
none
@Description
This function measures Frequency and Duty cycle of the input signal given by signal measurement
**/
void FrequencyAndDutycycleMeasurement(void)
{
uint8_t decValue = 0;
if (samplescount == MAXSAMPLES_COUNT) {
// Sum of period and pulse width samples value of input signal
// is copied to perioAfterCapture and pulseWidthAfterCature variable
periodAfterCapture = periodSum;
pulseWidthAfterCapture = pulseWidthSum;
// Averaging of the samples
periodAfterCaptureAvg = (periodAfterCapture / MAXSAMPLES_COUNT);
pulseWidthAfterCaptureAvg = (pulseWidthAfterCapture / MAXSAMPLES_COUNT);
// Using formula to calculate the Frequency and Duty cycle of the signal
//captureDuty = ((pulseWidthAfterCaptureAvg * 100L) / periodAfterCaptureAvg);
captureFrequency = (F_CPU / pulseWidthAfterCaptureAvg);
periodSum = 0;
pulseWidthSum = 0;
samplescount = 0;
}
// If condition is executed for every one second of the RTC interrupt
if (rtcFlag == 1) {
//decValue = (captureDuty % MAXSAMPLES_COUNT);
// Prints measured Frequency and Duty cycle of the signal on terminal window.
//sprintf(buffer, "Duty cycle=%lu.%d%% \r\nFrequency=%luHz\r\n\n", captureDuty, decValue, captureFrequency);
sprintf(buffer, "Frequency=%luHz\r\n\n" ,captureFrequency);
SendString(buffer);
rtcFlag = 0;
captureDuty = 0;
captureFrequency = 0;
}
}
主函数main.c
#include <atmel_start.h>
#include <stdio.h>
#include "application.h"
int main(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
/* Replace with your application code */
while (1) {
FrequencyAndDutycycleMeasurement();
}
}
3.实验结果
首先看一下PWM模块所产生的波形
对应的串口输出
可以看到串口打印为20khz
利用信号发生器更换频率
信号发生器的输入
串口信息的反馈
总结
至此完成整个频率计的设计过程,随着频率的不断提高计算的频率精度会有一定程度的下降,可以进行一定的补偿来弥补。