PWMA B模块会资源互斥么
// 方案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; // 波形已捕捉完成
u8PWMB_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 = 0;
if(v == 0){ UART1_TxByte('0'); return; }
while(v && i >= 0){ buf = (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=0HzDuty=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;
u8sr1;
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模块里啊
关于您提出的“PWMA B模块是否会资源互斥”的问题,以下是对该问题的详细分析与解答:
在使用STC8H系列单片机的PWMA(增强型脉宽调制)模块时,模块间的资源互斥问题是一个非常关键的配置考量点。所谓“资源互斥”,通常是指不同模块或通道之间是否共享某些硬件资源(如定时器、计数器、比较寄存器等),从而导致在同时使用时产生冲突或不可预知的行为。
一、PWMA模块的结构概述
STC8H系列单片机内置的PWMA模块为增强型PWM模块,支持多通道输出、频率与占空比独立调节、死区控制等功能。该模块通常由一个主定时器和多个独立通道组成,每个通道可以配置为独立的PWM输出。PWMA模块一般分为A、B、C等多个子模块(如PWMAB、PWMAC等),用于实现更灵活的PWM输出控制。
二、PWMAB模块与其他模块的资源使用情况
以PWMAB模块为例,其资源使用情况需参考数据手册中的“模块资源映射”部分。通常情况下:
定时器资源:多个PWMA子模块可能共享同一个主定时器作为计数源。例如,PWMAA、PWMAB、PWMAC可能共用PWMA的主定时器(如PWMxTimer)。这种情况下,这些模块的频率将被统一控制,无法各自独立设置频率,但占空比可独立配置。
通道资源:每个子模块通常包含多个通道(如4个通道),这些通道在内部使用独立的比较寄存器,因此在占空比设置上互不干扰。
中断资源:中断向量也可能存在共享情况,例如多个模块的中断可能共用一个中断入口,需通过软件判断中断源。
三、资源互斥的具体表现
若PWMAB模块与其他模块(如PWMAA)共享主定时器资源,则在配置时需注意以下几点:
1. 频率设置互斥:若多个模块共享同一主定时器,则它们的PWM频率必须一致,无法独立设置不同频率。
2. 占空比独立设置:每个通道的占空比由各自的比较寄存器控制,因此即使频率一致,占空比仍可独立调节。
3. 死区控制共享:若模块支持死区控制功能,死区时间可能为全局配置,影响所有使用该模块的通道。
4. 输出引脚冲突:在配置PWMAB模块的输出通道时,需注意引脚复用问题,避免与其他外设(如UART、SPI等)或其它PWM通道发生引脚冲突。
四、如何判断是否互斥
要准确判断PWMAB模块是否与其他模块存在资源互斥,建议参考以下方法:
1. 查阅数据手册:查看“增强型PWM模块”章节中关于模块资源分配的描述,确认PWMAB与其他模块是否共享主定时器、比较寄存器、中断源等。
2. 查看寄存器映射:通过查看PWM寄存器的地址分布,判断不同模块是否使用相同的寄存器地址空间。
3. 查阅官方应用笔记或示例代码:STC官方通常会提供相关配置示例,说明模块间的使用限制。
五、解决资源互斥的方法
若确实存在资源互斥问题,可通过以下方式规避或解决:
合理规划模块使用:避免在同一主定时器下配置多个需要不同频率的PWM模块。
使用不同PWM模块:如需不同频率输出,可选择使用不同主定时器驱动的PWM模块(如PWMA与PWMB)。
软件模拟PWM:对于非关键通道,可考虑使用定时器+GPIO翻转的方式实现软件PWM,避免资源冲突。
使用外置PWM芯片:在资源紧张时,可外挂PWM驱动芯片以扩展输出通道。
六、总结
综上所述,PWMAB模块是否与其他模块存在资源互斥,取决于其是否共享主定时器、中断源、比较寄存器等关键硬件资源。在实际使用中,应通过查阅技术手册和测试验证来确认模块间的兼容性。合理规划模块使用顺序和资源分配,是确保系统稳定运行的关键。
如需进一步分析具体配置代码或验证模块间的冲突情况,欢迎提供更详细的代码片段或配置参数,我将进一步协助您进行分析与优化。
如有技术手册或具体型号需求,建议提供完整型号(如STC8H8K64U)以便提供更精确的技术支持。
[本文内容由国芯人工智能辅助生成,仅供参考]
https://www.stcaimcu.com/data/download/Datasheet/STC8H.pdf
神农鼎 发表于 2025-10-19 16:41
https://www.stcaimcu.com/data/download/Datasheet/STC8H.pdf
所以是要分成两个PWM来用么
可以,但是要注意公用一个计数器的问题。
梁工 发表于 2025-10-19 17:46
可以,但是要注意公用一个计数器的问题。
我现在这个程序这样能处理么
影响到我测频 这个帖子有介绍原因,并提供了相应的例子
https://www.stcaimcu.com/forum.p ... id=20283&pid=187876
同组PWM捕获测量的周期值与PWM输出的周期相同,都是ARRH,ARRL。
由于同一组的PWM输出和捕获同步,如果PWM输出直接反馈接入到同组PWM捕获接口,
则每次捕获都刚好PWM溢出,计算出的周期值始终是0。
使能PWM输出时,如果使用同组PWM捕获外部输入信号有异常值,
是由于在发生捕获动作时将当前的计数值保存到PWMx_CCRn里面,但由于使能了PWM输出,
所以计数值到PWMx_ARR后就立即归零了
(正常是计数到FFFF再归零,开启输出后计数值到ARR值就立即归零)。
解决方法:1. 同一组PWM里面如果要输出和捕获同时进行,将ARR设置为FFFF。
2. 修改捕获计数方法:cnt = ((cnt1 - cnt2) % (PWMA_ARR + 1));
3. 捕获/输出分开两组PWM,例如:PWMA捕获,PWMB输出。
三种方法都可以解决以上问题。
乘风飞扬 发表于 2025-10-20 09:04
这个帖子有介绍原因,并提供了相应的例子
https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost ...
好的我看一下
原来没有找到这个帖子
页:
[1]