- 打卡等级:偶尔看看III
- 打卡总天数:34
- 最近打卡:2025-10-30 10:47:29
已绑定手机
中级会员
- 积分
- 209
|
// 方案002
// 头文件
#include "STC8Hxxx.h"
// 引脚定义
// 宏定义
#define MAIN_Fosc 40000000UL // 40MHz
// 声明
// 数组
// 函数
void u32_to_ascii(u32 v); // 打印32位整数(去除前导0)
void u16_to_ascii(u16 j); // 将数据转成十进制文本并从串口1发送
void ReturnValue(void); // 从串口1返回周期和高电平时间
void PWMB_config(void); // PWM配置函数
void SetTimer2Baudraye(u16 dat); // 设置Timer2做波特率发生器
void UART1_config(u32 brt, u8 timer, u8 io); // UART1初始化函数
void UART1_TxByte(u8 dat); // 串口1查询发送一个字节函数
void PrintString1(u8 *puts); // 串口1字符串打印函数
// 变量
bit B_TX1_Busy; // 发送忙标志
bit B_Capture2; // 波形已捕捉完成
u8 PWMB_ISR_En; // 每个通道可以单独允许中断处理, bit4:通道4, bit3:通道3, bit2:通道2, bit1:通道1.
u16 ccr3; // 中断使用的中间变量, 用户层不可见
u16 period2; // 周期
u16 PulseHigh2; // 高电平时间, 占空比 = PulseHigh /period * 100%
// 函数模块
// 打印32位整数(去除前导0)
void u32_to_ascii(u32 v)
{
char buf[11];
int i = 10;
buf[i--] = 0;
if(v == 0){ UART1_TxByte('0'); return; }
while(v && i >= 0){ buf[i--] = (v%10)+'0'; v/=10; }
for(i=i+1; buf!=0; i++) UART1_TxByte(buf);
}
// 将数据转成十进制文本并从串口1发送
void u16_to_ascii(u16 j)
{
UART1_TxByte(j/10000+'0');
UART1_TxByte((j%10000)/1000+'0');
UART1_TxByte((j%1000)/100+'0');
UART1_TxByte((j%100)/10+'0');
UART1_TxByte( j%10+'0');
}
// 从串口1返回周期和高电平时间
void ReturnValue(void)
{
unsigned long psc,freq,duty_x10;
PrintString1("Period_count=");
u16_to_ascii(period2);
PrintString1(" High_count=");
u16_to_ascii(PulseHigh2);
// 预分频值
psc = (unsigned long)PWMB_PSCR + 1UL; // 预分频值
if(period2==0)
{
PrintString1(" Freq=0Hz Duty=0.0%\r\n");
return;
}
// 频率占空比计算
freq = (unsigned long)MAIN_Fosc / ((unsigned long)period2 * psc); // 频率Hz
duty_x10 = ((unsigned long)PulseHigh2 * 1000UL) / period2; // 占空比×10
// 显示格式分配
if(freq >= 1000)
{
unsigned long freq_khz_int = freq / 1000;
unsigned long freq_khz_dec = (freq % 1000) / 100;
PrintString1(" Freq=");
u32_to_ascii(freq_khz_int);
UART1_TxByte('.');
UART1_TxByte('0'+(unsigned char)freq_khz_dec);
PrintString1("kHz");
}
else
{
PrintString1(" Freq=");
u32_to_ascii(freq);
PrintString1("Hz");
}
UART1_TxByte(' ');
PrintString1("Duty=");
u32_to_ascii(duty_x10/10);
UART1_TxByte('.');
UART1_TxByte('0'+(unsigned char)(duty_x10%10));
UART1_TxByte('%');
UART1_TxByte(0x0d);
UART1_TxByte(0x0a);
}
// PWM配置函数
void PWMB_config(void)
{
P_SW2 |= 0x80; // SFR enable
PWMB_CCER1 = 0;
PWMB_CCER2 = 0;
PWMB_SR1 = 0;
PWMB_SR2 = 0;
PWMB_ENO = 0;
PWMB_PS = 0;
PWMB_IER = 0;
PWMB_ISR_En = 0;
PWMB_PSCR = 0;
PWMB_DTR = 0; // 无死区
PWMB_ARR = 230; // 总周期 2000us
// 通道2 → P5.4
PWMB_CCR2 = 115; // 延时1000us → 宽度1000us
PWMB_CCMR2 = (7<<4) + 8; // PWM模式2 + CCR预装载
PWMB_CCER1 |= 0x50; // 开启比较输出,高电平有效
PWMB_PS |= (1<<2); // 路由到 P5.4
PWMB_ENO |= 0x04; // IO使能 P5.4
PWMB_BKR = 0x80; // 主输出使能
PWMB_CR1 |= 0x08; // 单脉冲模式
PWMB_CCMR3 = 0x01;
PWMB_CCER2 |= 0x01;
PWMB_CCMR4 = 0x02;
PWMB_CCER2 |= 0x30;
PWMB_PS |= 1;
PWMB_ISR_En |= 0x08;
PWMB_ISR_En |= 0x10;
P3M0 &= ~0x08; P3M1 &= ~0x08;
P33 = 1;
PWMB_IER = PWMB_ISR_En;
PWMB_CR1 |= 0x01;
}
// 设置Timer2做波特率发生器
void SetTimer2Baudraye(u16 dat) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{
AUXR &= ~(1<<4); //Timer stop
AUXR &= ~(1<<3); //Timer2 set As Timer
AUXR |= (1<<2); //Timer2 set as 1T mode
TH2 = (u8)(dat >> 8);
TL2 = (u8)dat;
IE2 &= ~(1<<2); //禁止中断
AUXR |= (1<<4); //Timer run enable
}
// UART1初始化函数
void UART1_config(u32 brt, u8 timer, u8 io) // brt: 通信波特率, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1, =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7.
{
brt = 65536UL - (MAIN_Fosc / 4) / brt;
if(timer == 2) // 波特率使用定时器2
{
AUXR |= 0x01; // S1 BRT Use Timer2;
SetTimer2Baudraye((u16)brt);
}
else // 波特率使用定时器1
{
TR1 = 0;
AUXR &= ~0x01; // S1 BRT Use Timer1;
AUXR |= (1<<6); // Timer1 set as 1T mode
TMOD &= ~(1<<6); // Timer1 set As Timer
TMOD &= ~0x30; // Timer1_16bitAutoReload;
TH1 = (u8)(brt >> 8);
TL1 = (u8)brt;
ET1 = 0; // 禁止Timer1中断
INT_CLKO &= ~0x02; // Timer1不输出高速时钟
// INT_CLKO |= 0x02; // Timer1输出高速时钟
TR1 = 1; // 运行Timer1
}
if(io == 1) {S1_USE_P36P37(); P3n_standard(0xc0);} // 切换到 P3.6 P3.7
else if(io == 2) {S1_USE_P16P17(); P1n_standard(0xc0);} // 切换到 P1.6 P1.7
else {S1_USE_P30P31(); P3n_standard(0x03);} // 切换到 P3.0 P3.1
SCON = (SCON & 0x3f) | (1<<6); // 8位数据, 1位起始位, 1位停止位, 无校验
ES = 1; // 允许中断
REN = 1; // 允许接收
}
// 串口1查询发送一个字节函数
void UART1_TxByte(u8 dat)
{
B_TX1_Busy = 1; //标志发送忙
SBUF = dat; //发一个字节
while(B_TX1_Busy); //等待发送完成
}
// 串口1字符串打印函数
void PrintString1(u8 *puts)
{
for (; *puts != 0; puts++) UART1_TxByte(*puts);
}
// 主函数
void main(void)
{
P_SW2 |= 0x80; // SFR enable
P5M0 |= 0x10; P5M1 &= ~0x10; // P54推挽输出
PWMB_config();
UART1_config(115200UL, 1, 0); // brt: 通信波特率, timer=2: 波特率使用定时器2, 其它值: 使用Timer1做波特率. io=0: 串口1切换到P3.0 P3.1, =1: 切换到P3.6 P3.7, =2: 切换到P1.6 P1.7.
EA = 1;
while (1)
{
if(B_Capture2) // 波形2捕捉完成
{
B_Capture2 = 0;
ReturnValue(); // 串口1返回周期和高电平时间
}
PWMB_CR1 |= 0x01; // 触发一次单脉冲输出
}
}
// 中断服务函数
// 串口1中断函数
void UART1_ISR (void) interrupt UART1_VECTOR
{
if(RI)
{
RI = 0;
}
if(TI)
{
TI = 0;
B_TX1_Busy = 0;
}
}
// PWMB中断处理程序. 读取捕获数据
void PWMB_ISR(void) interrupt PWMB_VECTOR
{
u16 j;
u8 sr1;
sr1 = PWMB_SR1; // 为了快速, 中断标志用一个局部变量处理
PWMB_SR1 = 0; // 清除中断标志
PWMB_SR2 = 0; // 清除中断标志
sr1 &= PWMB_ISR_En; // 每个通道可以单独允许中断处理
if(sr1 & 0x08) // 通道3, CC3捕获上升沿中断, 一个周期结束, 新的周期开始
{
j = ccr3; // 上一个捕捉时刻
ccr3 = PWMB_CCR3; // 读取当前捕捉时刻
period2 = ccr3 - j; // 减去上一个捕捉时刻, 计算周期
B_Capture2 = 1; // 标志波形2已捕捉完成
}
if(sr1 & 0x10) // 通道4, CC4捕获下降沿中断, 计算高电平时间
{
PulseHigh2 = PWMB_CCR4 - ccr3; // 读取当前捕捉时刻, 计算高电平时间
}
}现在这个程序
单独验证单脉冲 和 测频的时候都是ok的
但是一旦把这两个功能都放进PWMB里面 测频出问题了 并且脉冲频率也从170khz降到了167Khz 是不是不能放在一个PWM模块里啊
|
|