具有位操作的正交信号生成
Quadrature signal generation with bit manipulation
我尝试生成正交信号,但操作可能最低。我使用 STM32 和 GPIO 引脚 B8 和 B9 发送信号。
一对引脚 8 和 9 有四个可能的选项,它们是顺时针方向的:
0/0 1/0 1/1 和 0/1
逆时针
0/0 0/1 1/1 1/0
我找不到按位快速设置或重置所选引脚位的方法。
此外,如果它是旋转编码器或线性编码器,我必须能够顺时针或逆时针旋转并随时改变方向。
感谢您的帮助
Bit-banging
按位思考,B9取B8的前值,B8取B9的倒数,倒数时反之。您交换这两个位,并根据方向与 0x100
或 0x200
异或。
inline void incB89(int down) {
uint32_t temp;
/* read the current output state */
temp = GPIOB->ODR;
/* modifying the significant bit-pair
don't care about overflow */
temp = (((temp & 0x100) << 1) | ((temp & 0x200) >> 1)) ^ (0x100 << down);
/* Setting the reset bits BR8 and BR9. This has the effect that
bits 8 and 9 will be copied into the ODR, and the rest will
be left alone */
temp |= ((1 << 24) | (1 << 25));
GPIOB->BSRR = temp;
}
使用计时器(或两个)
在大多数 STM32 系列控制器上,TIM4
通道 3 和 4 输出可以映射到 PB8 和 PB9。如果你有其中之一,这个定时器可以自主控制输出,不受代码、内存或中断延迟的影响。
- 根据控制器的参考手册设置 GPIO 模式和备用功能寄存器。
- 将通道 3 和 4 都配置为切换模式,将
TIM4->CCMR1
中的 OC1M
和 OC2M
位设置为 0b011
。
- 设置输入时钟、预分频器
PSC
并重新加载ARR
以达到所需频率的两倍,因为每个输出将在每个定时器周期切换一次。
- 设置
TIM4->CCR3=0
和TIM4->CCR4=(TIM4->ARR+1)/2
单向计数。将它们交换(当计数器停止时)以反转方向。
- 启用
TIM4->CCER
中的输出。
- 您可以通过设置或重置
TIM4->CR1
的 CEN
位来开始和停止计数。
- 要计算周期,您可以在
TIM4->DIER
中为切换或更新事件配置中断,或者使用另一个定时器作为 TIM4 的从属。
使用例如TIM3
来数:
- 将
TIM4->CR2
中的 MMS
位设置为 0b010
以在每次溢出时输出触发脉冲。
- 配置
TIM3->SMCR
外部时钟模式1,selectTIM4内部触发
- 将
TIM3->ARR
设置为所需的半周期数 - 1。
- 配置更新中断。
- 启动计数器。
定时器还有一些可能的技巧,比如使用从属触发的 DMA 突发从 table 更新主定时器的 ARR
和 CCR
寄存器=78=] 值。
我尝试生成正交信号,但操作可能最低。我使用 STM32 和 GPIO 引脚 B8 和 B9 发送信号。 一对引脚 8 和 9 有四个可能的选项,它们是顺时针方向的: 0/0 1/0 1/1 和 0/1 逆时针 0/0 0/1 1/1 1/0 我找不到按位快速设置或重置所选引脚位的方法。 此外,如果它是旋转编码器或线性编码器,我必须能够顺时针或逆时针旋转并随时改变方向。
感谢您的帮助
Bit-banging
按位思考,B9取B8的前值,B8取B9的倒数,倒数时反之。您交换这两个位,并根据方向与 0x100
或 0x200
异或。
inline void incB89(int down) {
uint32_t temp;
/* read the current output state */
temp = GPIOB->ODR;
/* modifying the significant bit-pair
don't care about overflow */
temp = (((temp & 0x100) << 1) | ((temp & 0x200) >> 1)) ^ (0x100 << down);
/* Setting the reset bits BR8 and BR9. This has the effect that
bits 8 and 9 will be copied into the ODR, and the rest will
be left alone */
temp |= ((1 << 24) | (1 << 25));
GPIOB->BSRR = temp;
}
使用计时器(或两个)
在大多数 STM32 系列控制器上,TIM4
通道 3 和 4 输出可以映射到 PB8 和 PB9。如果你有其中之一,这个定时器可以自主控制输出,不受代码、内存或中断延迟的影响。
- 根据控制器的参考手册设置 GPIO 模式和备用功能寄存器。
- 将通道 3 和 4 都配置为切换模式,将
TIM4->CCMR1
中的OC1M
和OC2M
位设置为0b011
。 - 设置输入时钟、预分频器
PSC
并重新加载ARR
以达到所需频率的两倍,因为每个输出将在每个定时器周期切换一次。 - 设置
TIM4->CCR3=0
和TIM4->CCR4=(TIM4->ARR+1)/2
单向计数。将它们交换(当计数器停止时)以反转方向。 - 启用
TIM4->CCER
中的输出。 - 您可以通过设置或重置
TIM4->CR1
的CEN
位来开始和停止计数。 - 要计算周期,您可以在
TIM4->DIER
中为切换或更新事件配置中断,或者使用另一个定时器作为 TIM4 的从属。
使用例如TIM3
来数:
- 将
TIM4->CR2
中的MMS
位设置为0b010
以在每次溢出时输出触发脉冲。 - 配置
TIM3->SMCR
外部时钟模式1,selectTIM4内部触发 - 将
TIM3->ARR
设置为所需的半周期数 - 1。 - 配置更新中断。
- 启动计数器。
定时器还有一些可能的技巧,比如使用从属触发的 DMA 突发从 table 更新主定时器的 ARR
和 CCR
寄存器=78=] 值。