C. Make it Alternating

文章讲述了如何通过C++编程解决一个关于字符串操作的问题,最少删除次数和生成不同序列的方法,利用组合数学思想计算所有可能的序列总数。

题目:

样例:

输入
3
10010
111
0101

输出
1 2
2 6
0 1

思路:

        数学组合问题,在这里中要求 ans1 和ans2 两个答案,其中 ans1 表示最少操作次数,这是最容易求的,难点在 ans2 ,这里 ans2 是组合求总数的问题。其次,我们记录操作数,所求的答案它们的初始化,也是需要考虑的地方。

第二个答案就是一个组合数学 1 2 还有 2 1 是两种不同的情况
然后部分不同的情况也会造成总的也会有不同的情况
比如 [12 12] [21 12] [12 21] [1  1  2  2] 等等等等

代码详解如下:

#include <iostream>
#include <unordered_map>
#define endl '\n'
#define YES puts("YES")
#define NO puts("NO")
#define umap unordered_map
#pragma GCC optimize(3,"Ofast","inline")
#define ___G std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
using namespace std;
const int N = 2e6 + 10,MOD = 998244353;

inline void solve()
{
	string s;
	cin >> s;
	int n = s.size();
	// ans1 表示最少操作删除的次数
	// ans2 表示有多少种不同的删除方法后序列
	// 这里 ans2 = 1 是因为至少有一种操作后的序列,
	// 操作次数是 0 ,也算是一种操作后的序列
	
	// 而这里 cnt = 1 , 是求 ans2 的组合性质,方法数之间相乘
	
	int ans1 = 0,ans2 = 1;
	int cnt = 1;
	
	for(int i = 1;i < n;++i)
	{
		// 如果相邻相同,那么删除的操作次数增加
		if(s[i] == s[i - 1]) ++cnt;
		else
		{
			// 这里 ans1 累加最少操作次数
			// cnt - 1 是因为初始化时 cnt = 1
			ans1 += cnt - 1;
			
			// 这里 cnt 不 - 1 是防止 cnt = 1 时 ans2 相乘后不为零
			// ans2 求操作删除的不同序列
			ans2 = ans2 * cnt % MOD;
			
			// 这里操作删除过后,恢复删除后的 cnt初始次数,即重新开始计数删除
			cnt = 1;
		}
	}
	// 这个操作是,防止一直都是相邻相同的情况
	if(cnt > 1)
	{
		// 这里 ans1 累加最少操作次数
		// cnt - 1 是因为初始化时 cnt = 1
		ans1 += cnt - 1;
		
		// 这里 cnt 不 - 1 是防止 cnt = 1 时 ans2 相乘后不为零
		// ans2 求操作删除的不同序列
		ans2 = ans2 * cnt % MOD;
		
		// 这里操作过后,恢复删除后的 cnt初始次数,即重新开始计数删除
		cnt = 1;
	}
	
	// 开始组合求不同操作次数的序列
	// 这里 now = 1 是至少有一种序列。 即  序列长度是 1 也是一种序列
	int now = 1;
	
	// 组合相乘
	for(int i = 1;i <= ans1;++i)
	{
		now = now * i % MOD;
	}
	
	// 总组合总数相乘
	ans2 = ans2 * now % MOD;
	
	cout << ans1 << ' ' << ans2 << endl;
}


int main()
{
//	freopen("a.txt", "r", stdin);
	___G;
	int _t = 1;
	cin >> _t;
	while (_t--)
	{
		solve();
	}

	return 0;
}

最后提交:

/*****************************************************************************/ /* Description */ /* USB Audio Class capture device for STM32F103. - 1 channel¹ - 192'000 samples per second - true 15 bits per sample Pins used: - PA1 - analog input - PC13² - onboard green LED, indicates USB address assignment - PC14² - external LED, indicates active state (recording) - PB15 - test signal, push-pull output if enabled Input range and output format: Input is the regular ADC one. No scaling or shifting is done. 12-bit ADC measures from Vref+ to Vref- (in case of Blue Pill they are internally connected to Vdda and Vssa: +3.3 V and GND respectively). For output, 8 12-bit samples are added together, then the sum is multiplied by 2 to compose 16-bit values. A value of 32768 is subtracted to make samples signed. Endianness is "little". Test signal: If enabled, it will produce 192000 toggles per second (96 kHz square wave) between Vdd and Vss. Even if it's not directly connected to the input it will generate a bit of noise. When test signal is connected to ADC input a waveform should be like alternating samples of a close to maximum amplitude. USB device has only one configuration, one interface altsetting, no audio controls such as mute or volume. ¹ - If someone wants to make 2-channel version, then he must write additional proper oversamples summation function, set ADC second channel and change channels number and sampling rate in the USB configuration descriptor. If done, then one would have 96 ksps and only 14 bits per sample. ² - Pins PC13-PC15 should only sink or source no more than 3 mA. */ /*****************************************************************************/ /* Includes */ #include "blue_pill.h" #include "usb.h" asm(".include \"descriptors_audio.s\""); /*****************************************************************************/ /* Common defines and vars */ #define F_CPU_MHz 72 /* Pin will be configured as push-pull output if 1 */ #define ENABLE_TEST_SIGNAL_ON_PB15 0 /* Decreases CPU usage even more - to ~6% when running from flash */ #define USE_FAST_ASM_COPY_FUNCTIOIN 1 /* LED on PC14 pin indicates active state - recording */ #define BB_RED_OUT BITBAND(GPIOC->ODR, 14) #define RED BB_RED_OUT #define RED_ON() BB_RED_OUT = 0 #define RED_OFF() BB_RED_OUT = 1 #define RED_TOGGLE() BB_RED_OUT ^= 1 /* Count of 16-bit samples * (8) oversamples - determines buffer size */ #define ADC_RAW_BUF_CNT ((8)*(192+52)) /* 3904 bytes */ uint16_t adc_raw_buffer[ADC_RAW_BUF_CNT] __attribute__((aligned(4))); /*****************************************************************************/ /* USB related functions, vars and defs */ #define N_EPs 2 /* Total number of endpoints used */ #define EP0_BUF_SZ 8 /* See `descriptors_audio.s` file */ #define EP1_BUF_SZ 0 /* Not used in this program */ const uint32_t ep_typ_adr[N_EPs] = { (EP_TYPE_CONTROL | EP0), (EP_TYPE_ISOCHRONOUS | EP1) }, bufs_sizes[N_EPs] = { EP0_BUF_SZ, EP1_BUF_SZ }; #define EPnR_CLEAR_CTR(ep, x) EPnR_CLEAR_CTR_RW(ep, x, ep_typ_adr[ep]) #define EPnR_SET_STAT_RX(ep, x) EPnR_SET_STAT_RX_RW(ep, x, ep_typ_adr[ep]) #define EPnR_SET_STAT_TX(ep, x) EPnR_SET_STAT_TX_RW(ep, x, ep_typ_adr[ep]) int32_t device_address, current_configuration, /* Currently not used */ interface_1_altsetting; extern uint16_t device_descriptor[], config_descriptor[], *string_descriptor[]; /* Setup packet */ struct { uint32_t bmRequestType; uint32_t bRequest; uint32_t wValue; uint32_t wIndex; uint32_t wLength; } SP; /* PMA buffers addresses in normal address space; 2 pointers (for tx/tx0/rx0 and rx/tx1/rx1 buffers) for each of N_EPs endpoints */ uint32_t *pma_bufs[N_EPs][2]; /* Buffers origins in PMA space (0..511) */ #define PMA_BUF0_ORG (N_EPs * 8) /* EP0; same for tx and rx */ #define PMA_BUF1_ORG (PMA_BUF0_ORG + EP0_BUF_SZ) /* EP1; same for tx0 and tx1 */ void init_ep0() { /* PMA buffers are arrays of `uint32_t` which can carry only 16-bit values */ pma_bufs[EP0][TX] = alloc_pma(EP0, TX, PMA_BUF0_ORG, 0); pma_bufs[EP0][RX] = alloc_pma(EP0, RX, PMA_BUF0_ORG, EP0_BUF_SZ); /* After reset USB->EPnR == 0; set STAT_RX = VALID; STAT_TX = STALL; */ EPnR[EP0] = ep_typ_adr[EP0] | (VALID<<12) | (STALL<<4); } void set_ep1_counters(uint32_t cnt) { BDT[EP1][TX0].count = cnt; BDT[EP1][TX1].count = cnt; } void init_ep1() { /* Single buffer: both pointers point to the same location */ pma_bufs[EP1][TX0] = alloc_pma(EP1, TX0, PMA_BUF1_ORG, 0); pma_bufs[EP1][TX1] = alloc_pma(EP1, TX1, PMA_BUF1_ORG, 0); set_ep1_counters(0); /* STAT_TX = VALID; */ EPnR[EP1] = ep_typ_adr[EP1] | (VALID<<4); } void init_endpoints() { init_ep0(); init_ep1(); } uint32_t reset_dma_counter() { /* Returns current couter value. CNDTR holds number of transfers, not bytes. */ uint32_t cndtr; cndtr = DMA1_Channel1->CNDTR; #define DMA_TRANSFER_SIZE_32 (0b1010 << 8) /* To reset counter DMA must be disabled first */ DMA1_Channel1->CCR = 0; DMA1_Channel1->CNDTR = ADC_RAW_BUF_CNT/2; asm("@ no push, please"); DMA1_Channel1->CCR = 1 | DMA_TRANSFER_SIZE_32 | DMA_CCR_MINC; return cndtr; } void copy_to_pma_x8_oversampled(uint16_t *from, uint32_t* to, uint32_t cnt) { /* Function execution time is ~78 (~120) μs when running from flash (RAM) at 72 MHz CPU clock. `cnt` is the number of samples to be written. */ uint32_t sample, i; for (i=0; i < cnt; i++) { sample = from[i*8 + 0] + from[i*8 + 1] + from[i*8 + 2] + from[i*8 + 3] + from[i*8 + 4] + from[i*8 + 5] + from[i*8 + 6] + from[i*8 + 7]; /* Only lower 2 bytes will be copied */ to[i] = sample * 2 - 0x8000; } /* Test expression: will zero first sample in every USB frame */ //~ to[0] = 0; } #if USE_FAST_ASM_COPY_FUNCTIOIN == 1 __attribute__((naked)) void copy_to_pma_x8_oversampled_fast(uint16_t *from, uint32_t* to, int32_t cnt) { /* Function execution time is ~52 (~78) μs when running from flash (RAM) at 72 MHz CPU clock. `from` - 12-bit data as uint16_t*; `to` - PMA buffer, uint16_t* as uint32_t*; `cnt` - number of samples to be written. */ asm(" push {r4,r5,r6} "); asm(" b 2f "); asm(" "); asm(" 1: "); asm(" ldmia r0!, {r3,r4,r5,r6} "); asm(" "); asm(" add r3, r4 "); asm(" add r3, r5 "); asm(" add r3, r6 "); asm(" add r3, r3, r3, lsr #16 "); asm(" "); asm(" lsls r3, #1 "); asm(" sub r3, #0x8000 "); asm(" "); asm(" str r3, [r1], #4 "); asm(" 2: "); asm(" subs r2, #1 "); asm(" bpl 1b "); asm(" "); asm(" pop {r4,r5,r6} "); asm(" bx lr "); } #endif #if 0 void start_systick_ms(uint32_t ms) { /* Maximum overflow time is 1.864 s. */ if (ms) { SysTick->LOAD = ms * 1000 * F_CPU_MHz / 8; SysTick->CTRL = 3; } else { SysTick->CTRL = 0; SysTick->VAL = 0; } } #endif /*****************************************************************************/ /* General USB functions */ void ep0_set_stat_tx(uint32_t status) { /* Compiles to 7 instructions */ EPnR_SET_STAT_TX(EP0, status); } /* Used as arg in `epn_tx()` calls in place of `cnt` value when `data` == NULL */ #define NEXT 0 void epn_tx(uint32_t ep, uint16_t *data, int32_t cnt) { /* -1 (any negative) for `bytes_remain` means send nothing; if it's 0 - zero-length packet will be sent. */ static int32_t bytes_remain[N_EPs]; static uint16_t *s_data[N_EPs]; if (data != NULL) { /* Initializatioin */ s_data[ep] = data; bytes_remain[ep] = cnt; } else { /* On `NEXT` iterations */ cnt = bytes_remain[ep]; } if (cnt >= 0) { if (cnt >= bufs_sizes[ep]) { cnt = bufs_sizes[ep]; bytes_remain[ep] -= cnt; } else { /* Last packet */ bytes_remain[ep] = -1; } /* Will copy even number of bytes (never less); `cnt` may be odd only at a final chunk */ s_data[ep] = copy_to_pma(s_data[ep], pma_bufs[ep][TX], cnt); BDT[ep][TX].count = cnt; /* Enable transfer */ ep0_set_stat_tx(VALID); } } void get_descriptor(uint32_t wValue, uint32_t wLength) { uint32_t desc_type = wValue >> 8, desc_index = wValue & 0xff; uint16_t *data, cnt; switch (desc_type) { case DESC_TYPE_DEVICE: data = device_descriptor; cnt = DESCRIPTOR_SIZE(data); break; case DESC_TYPE_CONFIG: data = config_descriptor; cnt = CONFIG_DESCRIPTOR_SIZE(data); break; case DESC_TYPE_STRING: data = string_descriptor[desc_index]; cnt = DESCRIPTOR_SIZE(data); break; default: ep0_set_stat_tx(STALL); return; } if (cnt > wLength) { cnt = wLength; } /* Send descriptor */ epn_tx(EP0, data, cnt); } #if 0 void class_request_handler(uint32_t rx_cnt) { uint16_t data = 0, cnt = 0; switch (SP.bRequest) { case 0x01: /* SET_CUR */ MUTED = pma_bufs[EP0][RX][0] & 0xff; break; case 0x81: /* GET_CUR */ data = MUTED; cnt = 1; break; default: ep0_set_stat_tx(STALL); return; } /* Send short data or zero-length packet (status) */ epn_tx(EP0, &data, cnt); } #endif void setup_handler() { /* Setup Packet is always 8 bytes */ SP.bmRequestType = pma_bufs[EP0][RX][0] & 0x60, /* Type only */ SP.bRequest = pma_bufs[EP0][RX][0] >> 8, SP.wValue = pma_bufs[EP0][RX][1], SP.wIndex = pma_bufs[EP0][RX][2], SP.wLength = pma_bufs[EP0][RX][3]; uint16_t data = 0, cnt = 0; if (SP.bmRequestType == 0 /* Standard */) { switch (SP.bRequest) { case GET_STATUS: cnt = 2; break; case SET_ADDRESS: device_address = SP.wValue; break; case GET_DESCRIPTOR: /* `wIndex` is Lang ID or zero */ get_descriptor(SP.wValue, SP.wLength); return; case SET_CONFIGURATION: /* current_configuration = SP.wValue; */ break; case GET_CONFIGURATION: /* data = current_configuration; */ data = 1; /* There's only one config #1 */ cnt = 1; break; case SET_INTERFACE: if (SP.wIndex == 1) { interface_1_altsetting = SP.wValue; } break; case GET_INTERFACE: if (SP.wIndex == 1) { data = interface_1_altsetting; } cnt = 1; break; default: ep0_set_stat_tx(STALL); return; } } else { #if 0 if (SP.bRequest & 0x80) { /* Handle Class IN request */ class_request_handler(0); return; } else { /* Wait for Class OUT data; see `ISR_usb()` */ } #else ep0_set_stat_tx(STALL); return; #endif } /* Send short data or zero-length packet (Status) */ epn_tx(EP0, &data, cnt); } void USB_LP_CAN1_RX0_IRQHandler() { /* Main USB interrupt routine. */ /* Bits SOF and SOFM have same position */ uint32_t istr = USB->ISTR, ep = istr & 0x0f, epnr = EPnR[ep], reset = istr & USB_ISTR_RESET, sof_int = (USB->CNTR & USB_CNTR_SOFM) & (istr & USB_ISTR_SOF), setup = epnr & SETUP, rx = epnr & CTR_RX, tx = epnr & CTR_TX; static uint32_t ep1_tx_ok = 0; if (reset) { /* Host must send reset requset to a device right after it's been attached. */ init_endpoints(); USB->ISTR = 0; USB->DADDR = USB_DADDR_EF; TIM1->CR1 = 0; //stop timer1 TIM1->CNT = 0; ep1_tx_ok = 0; return; } if (sof_int) { /* SOF interrupts are enabled after an EP1 tx. If data haven't been transmitted in previous frame, turn red led off and stop conversions and disable SOF interrupts; on Isochronous EPs exactly one transaction occurs every frame. */ if (!ep1_tx_ok) { RED_OFF(); /* Timer 1 triggers ADCs; as group conversion is used, they remain converting and requesting DMA till group end */ TIM1->CR1 = 0; //stop timer1 TIM1->CNT = 0; set_ep1_counters(0); /* Turn off SOF interrupts */ USB->CNTR &= ~USB_CNTR_SOFM; } ep1_tx_ok = 0; /* Clear SOF flag */ USB->ISTR = ~USB_ISTR_SOF; } if (rx) { /* On receiving a Control data packet MC sets both STATs to NAK. */ if (setup) { setup_handler(); } else { #if 0 /* Staus or Data phase */ uint32_t rx_cnt = BDT[ep][RX].count & 0x3ff; if (rx_cnt) { if (ep == EP0 && SP.bmRequestType != 0) { /* Handle Class OUT request data */ class_request_handler(rx_cnt); } } #endif } /* Also clears EPnR_SETUP bit */ EPnR_CLEAR_CTR(ep, CTR_RX); EPnR_SET_STAT_RX(ep, VALID); } if (tx) { EPnR_CLEAR_CTR(ep, CTR_TX); if (ep == EP0) { if (device_address && device_address > 0) { USB->DADDR = USB_DADDR_EF | device_address; device_address = -1; /* Indicate successful address assignment */ LED_ON(); } /* Transmit next if there's data; first tx started elsewhere */ epn_tx(ep, NULL, NEXT); } else if (ep == EP1) { ep1_tx_ok = 1; if (TIM1->CR1 == 0 /* stopped */) { RED_ON(); /* Clear excess conversions from previous session */ reset_dma_counter(); /* Turn on SOF interrupts */ USB->ISTR = ~USB_ISTR_SOF; USB->CNTR |= USB_CNTR_SOFM; } /* Start/continue Timer 1; enable Timer1 CC3 interrupt; at the worst case the interrupt will happen in 5.2 μs */ TIM1->SR = 0; TIM1->DIER = TIM_DIER_CC3IE; TIM1->CR1 = 1; } } } /* ISR_usb() */ void TIM1_CC_IRQHandler() { /* Timer1 CC3 interrupt. It is generated a little before CC1 event, at this moment previous DMA transactions for all 8 oversamples of an audio sample should already be over. Timer1 CC1 triggers ADC1 group conversion while every conversion of a group triggers DMA. Thus we have about 14 ADC cycles or 84 CPU cycles to reset DMA counter and copy first 2 samples. Interrupt entry/exit costs 12 CPU cycles. */ uint32_t samples_done, bytes_done, cndtr; cndtr = reset_dma_counter(); /* DMA copies 2 samples at a time; there are 8 oversamples */ samples_done = ADC_RAW_BUF_CNT/8 - cndtr/4; bytes_done = samples_done * 2; #if USE_FAST_ASM_COPY_FUNCTIOIN == 1 copy_to_pma_x8_oversampled_fast(adc_raw_buffer, pma_bufs[EP1][TX], samples_done); #else copy_to_pma_x8_oversampled(adc_raw_buffer, pma_bufs[EP1][TX], samples_done); #endif set_ep1_counters(bytes_done); /* You must use DSB if an interrupt/flag is cleared at the handler return */ TIM1->DIER = 0; __DSB(); } /*****************************************************************************/ /* Program entry */ int main() { { /* Configure clocks */ CONFIGURE_PLL(HSE, F_CPU_MHz); RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; } { /* Enable peripherals used (except USB) */ RCC->AHBENR |= RCC_AHBENR_DMA1EN; RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_ADC1EN | RCC_APB2ENR_ADC2EN | RCC_APB2ENR_TIM1EN; } { /* LEDs */ /* LED_OFF(); RED_OFF(); CONFIGURE_PIN(GPIOC, 13, O_OPEN_DRAIN); CONFIGURE_PIN(GPIOC, 14, O_OPEN_DRAIN); ~= */ GPIOC->ODR = (1<<13) | (1<<14); GPIOC->CRH = (O_OPEN_DRAIN << 13%8*4) | (O_OPEN_DRAIN << 14%8*4); } { /* ADCs */ /** ADC1 + ADC2 run @ 12 MHz performing 4 group conversions each. ADCs are triggered by Timer 1 CC1 & CC2 events. The result is then copyed by DMA1 channel 1 requested by ADC1. ADC2 starts 7 cycles before ADC1. At 12 MHz clock one ADC can make no more than 4 conversions per 192k audio sample: - one conversion lasts 14 ADC clock cycles; - 12e6 / 192e3 / 14 ~= 4.46. Maximum externel trigger conversion start delay is: 2/12 + 1/72 = 0.180 μs (from datasheet) **/ /* CONFIGURE_PIN(GPIOA, 0, I_ANALOG); */ CONFIGURE_PIN(GPIOA, 1, I_ANALOG); #define A1CH 1 #define A2CH 1 #define TRG_T1CC1 (0b000 << ADC_CR2_EXTSEL_Pos) #define TRG_T1CC2 (0b001 << ADC_CR2_EXTSEL_Pos) ADC1->CR1 = ADC_CR1_SCAN; ADC2->CR1 = ADC_CR1_SCAN; ADC1->SQR1 = (4-1) << ADC_SQR1_L_Pos; ADC2->SQR1 = (4-1) << ADC_SQR1_L_Pos; ADC1->SQR3 = (A1CH<<(0*5)) | (A1CH<<(1*5)) | (A1CH<<(2*5)) | (A1CH<<(3*5)); ADC2->SQR3 = (A2CH<<(0*5)) | (A2CH<<(1*5)) | (A2CH<<(2*5)) | (A2CH<<(3*5)); ADC1->CR2 = 1 | ADC_CR2_EXTTRIG | TRG_T1CC1 | ADC_CR2_DMA; ADC2->CR2 = 1 | ADC_CR2_EXTTRIG | TRG_T1CC2; /* Calibrate ADCs */ wait_us(6, F_CPU_MHz); ADC1->CR2 |= ADC_CR2_CAL; ADC2->CR2 |= ADC_CR2_CAL; while ((ADC1->CR2 | ADC2->CR2) & ADC_CR2_CAL); } { /* Timer 1 as ADC sync */ /** TIM1_ARR - a period of ADCs triggering. CC3 event has an important role of updating DMA counter at the exact momment of time. It also used as the test signal generator. To make CCx an ADC trigger CCxE and MOE must be enabled. **/ #if ENABLE_TEST_SIGNAL_ON_PB15 == 1 /* Test PWM signal, 192k Toggles per second */ CONFIGURE_PIN(GPIOB, 15, O_ALT_PUSH_PULL); #endif #define CC_PWM2 0b111 /* |_--| */ #define CC_TOGGLE 0b011 TIM1->ARR = F_CPU_MHz * 1000 / 192 - 1; TIM1->CCR1 = 32 + 7*6; TIM1->CCR2 = 32; TIM1->CCR3 = 32; TIM1->CCMR1 = (CC_PWM2 << 4) | (CC_PWM2 << 12); TIM1->CCMR2 = (CC_TOGGLE << 4); TIM1->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E | TIM_CCER_CC3NE; TIM1->BDTR = TIM_BDTR_MOE; NVIC_EnableIRQ(TIM1_CC_IRQn); } { /* DMA */ DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR; DMA1_Channel1->CMAR = (uint32_t)adc_raw_buffer; } { /* USB */ ENABLE_USB_PERIPHERAL(USB_CNTR_RESETM | USB_CNTR_CTRM); /** Make USB interrupt preemptible **/ NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 1); NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); } while (PWR /* :) */) { /* Infinite loop. Current CPU load is no more than 10% spent on summation of oversamples. */ __WFI(); } } /*****************************************************************************/ /* Interrupt vectors */ #if 0 void ISR_systick() { RED_TOGGLE(); } VECTOR(IRQ_SysTick, ISR_systick); #endif #ifndef USE_STM32_LD VECTOR(IRQ_TIM1_CC, TIM1_CC_IRQHandler); VECTOR(IRQ_USB_LP_CAN_RX0, USB_LP_CAN1_RX0_IRQHandler); #endif /*****************************************************************************/
06-10
这段代码实现了一个基于STM32F103的USB音频捕获设备,能够以192kHz采样率和15位精度采集单通道音频信号。以下是对代码中关键部分的解释,并提供一些相关问题供进一步探讨。 ### 关键部分解释 #### 1. **ADC配置** ```c /* ADCs */ ADC1->CR1 = ADC_CR1_SCAN; ADC2->CR1 = ADC_CR1_SCAN; ADC1->SQR1 = (4-1) << ADC_SQR1_L_Pos; ADC2->SQR1 = (4-1) << ADC_SQR1_L_Pos; ADC1->SQR3 = (A1CH<<(0*5)) | (A1CH<<(1*5)) | (A1CH<<(2*5)) | (A1CH<<(3*5)); ADC2->SQR3 = (A2CH<<(0*5)) | (A2CH<<(1*5)) | (A2CH<<(2*5)) | (A2CH<<(3*5)); ADC1->CR2 = 1 | ADC_CR2_EXTTRIG | TRG_T1CC1 | ADC_CR2_DMA; ADC2->CR2 = 1 | ADC_CR2_EXTTRIG | TRG_T1CC2; ``` **解释:** - 配置了两个ADC(ADC1和ADC2),每个ADC进行4次转换。 - 使用Timer1的CC1和CC2事件作为外部触发源,分别触发ADC1和ADC2。 - 启用了DMA功能,将ADC结果直接存储到`adc_raw_buffer`中。 #### 2. **USB端点初始化** ```c void init_ep0() { pma_bufs[EP0][TX] = alloc_pma(EP0, TX, PMA_BUF0_ORG, 0); pma_bufs[EP0][RX] = alloc_pma(EP0, RX, PMA_BUF0_ORG, EP0_BUF_SZ); EPnR[EP0] = ep_typ_adr[EP0] | (VALID<<12) | (STALL<<4); } void init_ep1() { pma_bufs[EP1][TX0] = alloc_pma(EP1, TX0, PMA_BUF1_ORG, 0); pma_bufs[EP1][TX1] = alloc_pma(EP1, TX1, PMA_BUF1_ORG, 0); set_ep1_counters(0); EPnR[EP1] = ep_typ_adr[EP1] | (VALID<<4); } ``` **解释:** - `init_ep0`初始化控制端点(EP0),设置其接收和发送缓冲区。 - `init_ep1`初始化等时端点(EP1),用于传输音频数据。 - 等时端点的数据传输速率固定,适合实时音频流。 #### 3. **数据处理与传输** ```c void copy_to_pma_x8_oversampled(uint16_t *from, uint32_t* to, uint32_t cnt) { uint32_t sample, i; for (i=0; i < cnt; i++) { sample = from[i*8 + 0] + from[i*8 + 1] + from[i*8 + 2] + from[i*8 + 3] + from[i*8 + 4] + from[i*8 + 5] + from[i*8 + 6] + from[i*8 + 7]; to[i] = sample * 2 - 0x8000; } } ``` **解释:** - 将8个过采样样本相加,乘以2并减去`0x8000`,生成16位有符号样本。 - 这种方法提高了信噪比,同时保持了15位的有效精度。 #### 4. **中断处理** ```c void USB_LP_CAN1_RX0_IRQHandler() { if (reset) { init_endpoints(); USB->ISTR = 0; USB->DADDR = USB_DADDR_EF; TIM1->CR1 = 0; //stop timer1 TIM1->CNT = 0; ep1_tx_ok = 0; return; } if (sof_int) { if (!ep1_tx_ok) { RED_OFF(); TIM1->CR1 = 0; //stop timer1 TIM1->CNT = 0; set_ep1_counters(0); USB->CNTR &= ~USB_CNTR_SOFM; } ep1_tx_ok = 0; USB->ISTR = ~USB_ISTR_SOF; } if (rx) { if (setup) { setup_handler(); } else { EPnR_CLEAR_CTR(ep, CTR_RX); EPnR_SET_STAT_RX(ep, VALID); } } if (tx) { EPnR_CLEAR_CTR(ep, CTR_TX); if (ep == EP0) { epn_tx(ep, NULL, NEXT); } else if (ep == EP1) { ep1_tx_ok = 1; TIM1->SR = 0; TIM1->DIER = TIM_DIER_CC3IE; TIM1->CR1 = 1; } } } ``` **解释:** - 处理USB复位、帧开始(SOF)、接收和发送中断。 - 在EP1发送完成后,重新启动Timer1以继续采集音频数据。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值