- 打卡等级:初来乍到
- 打卡总天数:4
- 最近打卡:2025-08-29 08:03:13
已绑定手机
注册会员
- 积分
- 56
|
我改用T0计数,自己测试的时候1Hz-2Mhz 都还勉强过的去,拿给别人测试回来发现,数据跳动很大,也很不稳定,又全乱了,低频更是离谱,麻烦帮我分析一下原因。P34 P35短接的
#include <STC15.H>
#include <intrins.h>
//------------------------------------------------------------------
// 类型定义
//------------------------------------------------------------------
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
//------------------------------------------------------------------
// LCD引脚定义
//------------------------------------------------------------------
sbit LCD_RS = P3 ^ 2;
sbit LCD_RW = P3 ^ 3;
sbit LCD_EN = P3 ^ 7;
#define LCD_DATA P1
//------------------------------------------------------------------
// 全局变量定义
//------------------------------------------------------------------
#define RNG_HIGH 0
#define RNG_MID 1
#define RNG_LOW 2
volatile u8 range;
volatile u8 range_changed;
volatile u16 gate_ticks;
volatile u16 gate_counter;
volatile u16 t0_overflow_count;
volatile u32 raw_count;
volatile bit data_ready;
volatile bit measure_done;
#define FILTER_SIZE 3
u32 freq_buffer[FILTER_SIZE];
u8 buffer_index;
u32 filtered_freq;
u16 gate_time_ms;
char disp_buf[9];
//------------------------------------------------------------------
// LCD驱动函数
//------------------------------------------------------------------
void delay_ms(u16 n)
{
u16 i, j;
for (i = n; i > 0; i--)
for (j = 1140; j > 0; j--)
;
}
void lcd_busy_check()
{
delay_ms(2);
}
void lcd_write_cmd(u8 cmd)
{
lcd_busy_check();
LCD_RS = 0;
LCD_RW = 0;
LCD_DATA = cmd;
LCD_EN = 1;
_nop_();
_nop_();
LCD_EN = 0;
}
void lcd_write_data(u8 dat)
{
lcd_busy_check();
LCD_RS = 1;
LCD_RW = 0;
LCD_DATA = dat;
LCD_EN = 1;
_nop_();
_nop_();
LCD_EN = 0;
}
void lcd_set_cursor(u8 pos)
{
lcd_write_cmd(0x80 | pos);
}
void lcd_init()
{
delay_ms(15);
lcd_write_cmd(0x38);
delay_ms(5);
lcd_write_cmd(0x38);
delay_ms(100);
lcd_write_cmd(0x38);
delay_ms(100);
lcd_write_cmd(0x38);
lcd_write_cmd(0x0C);
lcd_write_cmd(0x06);
lcd_write_cmd(0x01);
delay_ms(2);
}
void lcd_show_string(u8 pos, u8 *str, u8 len)
{
u8 i;
lcd_set_cursor(pos);
for (i = 0; i < len; i++)
{
lcd_write_data(str);
}
}
//------------------------------------------------------------------
// 数字转字符串函数(显示原始数据)
//------------------------------------------------------------------
/*void num_to_str(u32 num, u8 *buf)
{
u8 i;
u8 digits = 0;
u32 temp = num;
// 计算位数
do
{
digits++;
temp /= 10;
} while (temp > 0);
// 数字转字符
temp = num;
for (i = 0; i < digits; i++)
{
buf[digits - 1 - i] = '0' + (temp % 10);
temp /= 10;
}
// 前面补空格
for (i = digits; i < 8; i++)
{
buf = ' ';
}
buf[8] = '\0';
}*/
void freq_to_str(u32 freq_hz, u8 *buf)
{
u8 i;
if (freq_hz >= 1000000)
{
// 1MHz及以上:显示为X.X MHz
u32 temp = freq_hz / 100000; // 转换为0.1MHz单位
buf[0] = '0' + (temp / 10); // 整数位
buf[1] = '.';
buf[2] = '0' + (temp % 10); // 一位小数
buf[3] = 'M';
buf[4] = 'H';
buf[5] = 'z';
buf[6] = ' ';
buf[7] = ' ';
}
else if (freq_hz >= 100000)
{
// 100kHz-999kHz:显示为XXX.X kHz
u32 temp = freq_hz / 100; // 转换为0.1kHz单位
buf[0] = '0' + (temp / 1000) % 10; // 百位
buf[1] = '0' + (temp / 100) % 10; // 十位
buf[2] = '0' + (temp / 10) % 10; // 个位
buf[3] = '.';
buf[4] = '0' + (temp % 10); // 一位小数
buf[5] = 'k';
buf[6] = 'H';
buf[7] = 'z';
}
else if (freq_hz >= 10000)
{
// 10kHz-99.9kHz:显示为XX.X kHz
u32 temp = freq_hz / 100; // 转换为0.1kHz单位
buf[0] = '0' + (temp / 100) % 10; // 十位
buf[1] = '0' + (temp / 10) % 10; // 个位
buf[2] = '.';
buf[3] = '0' + (temp % 10); // 一位小数
buf[4] = 'k';
buf[5] = 'H';
buf[6] = 'z';
buf[7] = ' ';
}
else if (freq_hz >= 1000)
{
// 1kHz-9.9kHz:显示为X.X kHz
u32 temp = freq_hz / 100; // 转换为0.1kHz单位
buf[0] = '0' + (temp / 10); // 整数位
buf[1] = '.';
buf[2] = '0' + (temp % 10); // 一位小数
buf[3] = 'k';
buf[4] = 'H';
buf[5] = 'z';
buf[6] = ' ';
buf[7] = ' ';
}
else
{
// 1Hz以下:显示为XXX Hz
if (freq_hz == 0)
{
buf[0] = '0';
buf[1] = ' ';
buf[2] = 'H';
buf[3] = 'z';
for (i = 4; i < 8; i++)
buf = ' ';
}
else
{
// 计算位数
u8 digits = 0;
u32 temp = freq_hz;
do
{
digits++;
temp /= 10;
} while (temp > 0);
// 数字转字符
temp = freq_hz;
for (i = 0; i < digits; i++)
{
buf[digits - 1 - i] = '0' + (temp % 10);
temp /= 10;
}
// 添加单位
buf[digits] = ' ';
buf[digits + 1] = 'H';
buf[digits + 2] = 'z';
// 后面补空格
for (i = digits + 3; i < 8; i++)
{
buf = ' ';
}
}
}
buf[8] = '\0';
}
//------------------------------------------------------------------
// 指数平滑滤波
// Y(n) = α × X(n) + (1-α) × Y(n-1)
// Y(n):当前滤波后的输出值
// X(n):当前输入的新值
// Y(n-1):上一次滤波后的输出值
// α:平滑系数(0 < α < 1)a值越小,平滑效果越强,响应越慢,显示越慢越稳定
// 推荐α值:
// 低频信号:α = 0.2(强平滑)
// 中频信号:α = 0.3(中等平滑)
// 高频信号:α = 0.4(弱平滑)
//------------------------------------------------------------------
u32 median_filter(u32 new_value)
{
static u32 filtered = 0;
if (filtered == 0)
{
filtered = new_value;
}
else
{
// 平滑系数可调:数值越小越平滑,但响应越慢
filtered = (filtered * 7 + new_value * 3) / 10;
}
return filtered;
}
//------------------------------------------------------------------
// 频率计算和量程自动切换
//------------------------------------------------------------------
void process_measurement_data()
{
u32 current_freq;
u8 new_range;
u8 i;
if (!data_ready)
return;
// 计算频率 (Hz) = 计数值 / (闸门时间/1000)
current_freq = raw_count * 1000UL / gate_time_ms;
filtered_freq = median_filter(current_freq);
// 量程自动切换
new_range = range;
if (range == RNG_HIGH)
{
if (filtered_freq < 8000)
new_range = RNG_MID;
}
else if (range == RNG_MID)
{
if (filtered_freq > 9500)
new_range = RNG_HIGH;
else if (filtered_freq < 400)
new_range = RNG_LOW;
}
else if (range == RNG_LOW)
{
if (filtered_freq > 450)
new_range = RNG_MID;
}
if (new_range != range)
{
range = new_range;
range_changed = 1;
if (range == RNG_HIGH)
{
gate_ticks = 2; // 20ms
gate_time_ms = 20;
}
else if (range == RNG_MID)
{
gate_ticks = 20; // 200ms
gate_time_ms = 200;
}
else if (range == RNG_LOW)
{
gate_ticks = 200; // 2000ms
gate_time_ms = 2000;
}
gate_counter = gate_ticks;
for (i = 0; i < FILTER_SIZE; i++)
{
freq_buffer = 0;
}
buffer_index = 0;
}
data_ready = 0;
measure_done = 1;
}
//------------------------------------------------------------------
// IO口初始化
//------------------------------------------------------------------
void io_init()
{
// P3.4 P3.5 设置为高阻输入 P3.2 P3.3 P.7 设置为推挽输出
P3M1 = 0x30;
P3M0 = 0x8c;
// LCD数据端口设置为准双向口
P1M1 = 0x00;
P1M0 = 0x00;
}
//------------------------------------------------------------------
// 定时器初始化(T0 1分频,T2 12分频)
//------------------------------------------------------------------
void timer_init()
{
// 初始化变量
range = RNG_MID;
range_changed = 0;
gate_ticks = 20; // 初始200ms
gate_counter = 20;
gate_time_ms = 200;
t0_overflow_count = 0;
raw_count = 0;
data_ready = 0;
measure_done = 0;
buffer_index = 0;
filtered_freq = 0;
// 清空滤波缓冲区
for (buffer_index = 0; buffer_index < FILTER_SIZE; buffer_index++)
{
freq_buffer[buffer_index] = 0;
}
buffer_index = 0;
// T0 配置:计数器模式,1T模式(1分频)
TMOD &= 0xF0; // 清除T0相关设置
TMOD |= 0x00; // 设置为模式0(16位自动重装载)
TMOD |= (1 << 2); // 设置为外部计数模式
AUXR &= 0x7F; // 清除AUXR最高位
AUXR |= 0x80; // T0 1T模式(1分频)
TH0 = 0;
TL0 = 0;
AUXR &= 0xE3; // 0xE3 = 1110 0011//设置T2 为12T分频,用作定时器
T2L = 0x00; // 设置定时初始值10ms
T2H = 0xDC; // 设置定时初始值10ms
TR0 = 1; // 启动T0
ET0 = 1; // 使能T0中断
AUXR |= 0x10; // 启动T2
IE2 |= 0x04; // 使能T2中断
EA = 1; // 使能全局中断
}
//------------------------------------------------------------------
// 中断服务函数
//------------------------------------------------------------------
void timer0_isr() interrupt 1
{
t0_overflow_count++;
}
void timer2_isr() interrupt 12
{
u32 total_count;
if (--gate_counter == 0)
{
gate_counter = gate_ticks;
TR0 = 0;
ET0 = 0;
total_count = (u32)t0_overflow_count * 65536UL + (TH0 << 8) + TL0;
TH0 = 0;
TL0 = 0;
t0_overflow_count = 0;
TR0 = 1;
ET0 = 1;
raw_count = total_count;
data_ready = 1;
}
}
//------------------------------------------------------------------
// 主函数
//------------------------------------------------------------------
void main()
{
u8 freq_str[8];
io_init();
lcd_init();
timer_init();
// 显示固定标题
lcd_show_string(0x80, "Waiting.", 8);
while (1)
{
process_measurement_data();
if (measure_done && !range_changed)
{
// 显示原始频率数值
freq_to_str(filtered_freq, freq_str);
lcd_show_string(0x80, freq_str, 8);
measure_done = 0;
}
if (range_changed)
{
range_changed = 0;
measure_done = 0;
}
}
}
|
|