作为一款高性能微控制器,STM32G474系列的中断系统设计颇具特色。在实际项目中,合理配置中断能显著提升系统响应效率。下面以EXTI外部中断为例,演示完整配置流程。
STM32G474的中断控制器支持多达150个中断向量,其中EXTI线0-15对应不同的GPIO引脚。以PA0配置为例,需要明确以下映射关系:
c复制// PA0对应EXTI线0
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
这里EXTICR寄存器组的索引计算方式为:EXTICR[EXTI线编号/4]。每个寄存器管理4个EXTI线,通过4位字段选择具体引脚。
STM32G474采用4位优先级分组,建议采用以下分组方式:
c复制NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
优先级数值越小等级越高,注意:
c复制void EXTI0_IRQHandler(void) {
if(EXTI->PR1 & EXTI_PR1_PIF0) {
// 中断处理逻辑
EXTI->PR1 = EXTI_PR1_PIF0; // 清除中断标志
}
}
void configure_interrupt(void) {
// 使能SYSCFG时钟
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
// 配置PA0为输入
GPIOA->MODER &= ~GPIO_MODER_MODE0;
// 映射PA0到EXTI0
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PA;
// 配置EXTI0为上升沿触发
EXTI->RTSR1 |= EXTI_RTSR1_RT0;
EXTI->FTSR1 &= ~EXTI_FTSR1_FT0;
// 使能EXTI0中断
EXTI->IMR1 |= EXTI_IMR1_IM0;
// 配置NVIC
NVIC_SetPriority(EXTI0_IRQn, 0x03);
NVIC_EnableIRQ(EXTI0_IRQn);
}
关键提示:STM32G474的EXTI控制器分为EXTI0_1、EXTI2_3等多个IRQ通道,需要根据实际使用的EXTI线选择正确的中断服务函数。
Vue3的v-model在Composition API下有了更多灵活用法,下面通过典型场景展示其核心机制。
对于自定义输入组件,标准实现方式如下:
vue复制<!-- CustomInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
使用时通过v-model绑定:
vue复制<CustomInput v-model="searchText" />
Vue3支持为单个组件绑定多个v-model:
vue复制<!-- UserNameForm.vue -->
<script setup>
defineProps({
firstName: String,
lastName: String
})
defineEmits(['update:firstName', 'update:lastName'])
</script>
<template>
<input
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
使用时可这样绑定:
vue复制<UserNameForm
v-model:firstName="first"
v-model:lastName="last"
/>
自定义修饰符需要通过computed属性实现:
vue复制<script setup>
import { computed } from 'vue'
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})
const emit = defineEmits(['update:modelValue'])
function emitValue(e) {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
使用时添加修饰符:
vue复制<CustomInput v-model.capitalize="text" />
在数据采集系统中,合理的中断配置能显著提升吞吐量:
c复制// 配置ADC使用DMA传输
ADC1->CFGR |= ADC_CFGR_DMAEN;
DMA1_Channel1->CCR |= DMA_CCR_TCIE; // 传输完成中断
__attribute__((section(".fastcode")))将ISR放在RAM执行__ALWAYS_INLINE内联对于高频更新的数据绑定:
js复制import { shallowRef } from 'vue'
// 适合不需要深度响应的场景
const fastData = shallowRef({ value: 0 })
使用防抖优化输入绑定:
vue复制<script setup>
import { debounce } from 'lodash-es'
const searchText = ref('')
const updateSearch = debounce((value) => {
searchText.value = value
}, 300)
</script>
<template>
<input @input="updateSearch($event.target.value)" />
</template>
问题1:中断无法触发
NVIC_EnableIRQ)问题2:中断频繁触发
c复制void EXTI0_IRQHandler(void) {
static uint32_t lastTick = 0;
if(HAL_GetTick() - lastTick < 10) return;
lastTick = HAL_GetTick();
// 正常处理逻辑
}
问题1:v-model不更新
defineProps和defineEmitsupdate:modelValue问题2:修饰符不生效
modelModifiers属性对于复杂外设,可采用中断分级处理:
c复制void TIM1_UP_IRQHandler(void) {
// 一级中断:仅做标记
g_tim1Flag = true;
TIM1->SR = ~TIM_SR_UIF;
}
void main_loop() {
while(1) {
if(g_tim1Flag) {
g_tim1Flag = false;
// 二级处理:实际业务逻辑
}
}
}
将v-model与Pinia结合使用:
js复制// stores/form.js
import { defineStore } from 'pinia'
export const useFormStore = defineStore('form', {
state: () => ({ inputValue: '' }),
getters: {
processedValue: (state) => state.inputValue.toUpperCase()
}
})
组件中使用:
vue复制<script setup>
import { useFormStore } from './stores/form'
import { storeToRefs } from 'pinia'
const store = useFormStore()
const { inputValue } = storeToRefs(store)
</script>
<template>
<input v-model="inputValue" />
</template>
在调试复杂中断系统时,逻辑分析仪是必不可少的工具。我习惯使用Saleae Logic Pro 16配合PulseView软件,可以同时捕获多个GPIO状态和中断触发时序。一个实用的技巧是在中断服务函数开始和结束位置添加GPIO电平翻转语句,这样就能直观测量中断延迟和执行时间:
c复制void EXTI0_IRQHandler(void) {
GPIOB->BSRR = GPIO_BSRR_BS_0; // 置高PB0
// 中断处理逻辑
GPIOB->BSRR = GPIO_BSRR_BR_0; // 置低PB0
}