Конечно. Ниже приведены полные листинги файлов `main.c` и `init.c` для Лабораторных работ 1, 2, 3, 4 и 6. Код написан с использованием библиотеки **Standard Peripheral Library (SPL)**, как это требуется в методическом пособии.

---

### Лабораторная работа 1: GPIO (Мигание светодиодами)
**Задача:** Поочередное циклическое включение светодиодов (Зеленый -> Оранжевый -> Красный -> Синий).

#### `init.c`
```c
#include "init.h"

void LEDs_ini(void) {
    GPIO_InitTypeDef GPIO_Init_LED;
    
    // 1. Включаем тактирование порта D (где сидят светодиоды)
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    // 2. Настраиваем пины 12, 13, 14, 15
    GPIO_Init_LED.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init_LED.GPIO_Mode = GPIO_Mode_OUT;      // Режим: Выход
    GPIO_Init_LED.GPIO_Speed = GPIO_Speed_2MHz;   // Скорость: Низкая (экономия энергии)
    GPIO_Init_LED.GPIO_OType = GPIO_OType_PP;     // Тип: Push-Pull (тяни-толкай)
    GPIO_Init_LED.GPIO_PuPd = GPIO_PuPd_NOPULL;   // Без подтяжки
    
    // 3. Применяем настройки
    GPIO_Init(GPIOD, &GPIO_Init_LED);
}
```

#### `main.c`
```c
#include "main.h"

// Простая функция задержки на цикле
void Delay(volatile uint32_t nCount) {
    while(nCount--) {}
}

int main(void) {
    LEDs_ini(); // Вызов инициализации

    while(1) {
        // Зеленый (PD12)
        GPIO_SetBits(GPIOD, GPIO_Pin_12);
        Delay(2000000);
        GPIO_ResetBits(GPIOD, GPIO_Pin_12);

        // Оранжевый (PD13)
        GPIO_SetBits(GPIOD, GPIO_Pin_13);
        Delay(2000000);
        GPIO_ResetBits(GPIOD, GPIO_Pin_13);

        // Красный (PD14)
        GPIO_SetBits(GPIOD, GPIO_Pin_14);
        Delay(2000000);
        GPIO_ResetBits(GPIOD, GPIO_Pin_14);

        // Синий (PD15)
        GPIO_SetBits(GPIOD, GPIO_Pin_15);
        Delay(2000000);
        GPIO_ResetBits(GPIOD, GPIO_Pin_15);
    }
}
```

---

### Лабораторная работа 2: Прерывания и таймеры
**Задача:** Переключение режимов мигания (Красный 8с / Синий 3с) по нажатию кнопки через прерывание.

#### `init.c`
```c
#include "init.h"

// Настройка светодиодов
void LEDs_ini(void) {
    GPIO_InitTypeDef GPIO_Init_LED;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    GPIO_Init_LED.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init_LED.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init_LED.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init_LED.GPIO_OType = GPIO_OType_PP;
    GPIO_Init_LED.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_Init_LED);
}

// Настройка кнопки (PA0)
void Button_ini(void) {
    GPIO_InitTypeDef GPIO_Init_Button;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    
    GPIO_Init_Button.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init_Button.GPIO_Mode = GPIO_Mode_IN; // Режим: Вход
    GPIO_Init_Button.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init_Button.GPIO_OType = GPIO_OType_PP;
    GPIO_Init_Button.GPIO_PuPd = GPIO_PuPd_NOPULL; // PA0 уже имеет внешнюю подтяжку к земле на плате
    GPIO_Init(GPIOA, &GPIO_Init_Button);
}

// Настройка внешних прерываний (EXTI) для кнопки
void EXTI_Config(void) {
    EXTI_InitTypeDef EXTI_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    // Включаем тактирование SYSCFG
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

    // Подключаем EXTI Line0 к порту PA0
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

    // Настраиваем линию EXTI0
    EXTI_InitStruct.EXTI_Line = EXTI_Line0;
    EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising; // Срабатывание по переднему фронту (нажатие)
    EXTI_InitStruct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStruct);

    // Настраиваем прерывание в NVIC (контроллере прерываний)
    NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}
```

#### `main.c`
```c
#include "main.h"

volatile uint32_t ms_ticks = 0;
volatile uint8_t mode = 0; // 0 - режим красного, 1 - режим синего

// Обработчик системного таймера (вызывается каждую 1 мс)
void SysTick_Handler(void) {
    ms_ticks++;
}

// Обработчик прерывания от кнопки
void EXTI0_IRQHandler(void) {
    // Проверяем флаг прерывания
    if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
        // Программный антидребезг (задержка)
        for(int i=0; i<100000; i++); 
        
        // Если кнопка все еще нажата
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET) {
            mode = !mode; // Инвертируем режим
            
            // Гасим оба диода, чтобы начать цикл заново чисто
            GPIO_ResetBits(GPIOD, GPIO_Pin_14 | GPIO_Pin_15);
            ms_ticks = 0; // Сброс таймера цикла
        }
        // Очищаем флаг прерывания
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

int main(void) {
    LEDs_ini();
    Button_ini();
    EXTI_Config();
    
    // Настройка SysTick на 1 мс (если частота ядра 168МГц или другая - функция сама посчитает)
    SysTick_Config(SystemCoreClock / 1000);

    while(1) {
        if (mode == 0) {
            // Режим Красный: Период 8000 мс (4с горит, 4с не горит)
            if ((ms_ticks % 8000) < 4000) 
                GPIO_SetBits(GPIOD, GPIO_Pin_14);
            else 
                GPIO_ResetBits(GPIOD, GPIO_Pin_14);
        } 
        else {
            // Режим Синий: Период 3000 мс (1.5с горит, 1.5с не горит)
            if ((ms_ticks % 3000) < 1500) 
                GPIO_SetBits(GPIOD, GPIO_Pin_15);
            else 
                GPIO_ResetBits(GPIOD, GPIO_Pin_15);
        }
    }
}
```

---

### Лабораторная работа 3: UART (Связь с ПК)
**Задача:** Отправка сообщений в консоль и управление миганием по кнопке.

#### `init.c`
```c
#include "init.h"

// Светодиоды и Кнопка настраиваются так же, как и раньше
void LEDs_ini(void) {
    GPIO_InitTypeDef GPIO_Init_LED;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
    GPIO_Init_LED.GPIO_Pin = GPIO_Pin_12; // Используем зеленый
    GPIO_Init_LED.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Init_LED.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init_LED.GPIO_OType = GPIO_OType_PP;
    GPIO_Init_LED.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &GPIO_Init_LED);
}

void Button_ini(void) {
    GPIO_InitTypeDef GPIO_Init_Button;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    GPIO_Init_Button.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init_Button.GPIO_Mode = GPIO_Mode_IN;
    GPIO_Init_Button.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_Init_Button);
}

// Настройка USART2 (PA2 - TX, PA3 - RX)
void USART2_ini(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 1. Включаем тактирование GPIOA и USART2
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

    // 2. Настраиваем пины PA2 и PA3 на альтернативную функцию
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. Соединяем пины с альтернативной функцией AF7 (USART2)
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);

    // 4. Настраиваем параметры USART
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    
    USART_Init(USART2, &USART_InitStructure);
    USART_Cmd(USART2, ENABLE); // Включаем USART
}
```

#### `main.c`
```c
#include "main.h"
#include <stdio.h>

volatile uint8_t is_blinking = 0; 
volatile uint32_t timer_ms = 0;

// Переопределение fputc для работы printf через UART
struct __FILE { int handle; };
FILE __stdout;
int fputc(int ch, FILE *f) {
    USART_SendData(USART2, (uint8_t)ch);
    while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){}
    return ch;
}

// Таймер для отсчета времени
void SysTick_Handler(void) {
    if (is_blinking) {
        timer_ms++;
        if (timer_ms >= 200) { // Каждые 200 мс переключаем диод
            GPIO_ToggleBits(GPIOD, GPIO_Pin_12);
            timer_ms = 0;
        }
    } else {
        GPIO_ResetBits(GPIOD, GPIO_Pin_12);
    }
}

int main(void) {
    LEDs_ini();
    Button_ini();
    USART2_ini();
    SysTick_Config(SystemCoreClock / 1000);

    uint8_t btn_prev = 0;

    while(1) {
        // Опрос кнопки
        uint8_t btn_curr = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
        
        if (btn_curr == 1 && btn_prev == 0) { // Нажатие (передний фронт)
            is_blinking = !is_blinking; // Смена состояния
            
            if (is_blinking) {
                printf("LED Status: BLINKING\r\n");
            } else {
                printf("LED Status: STOPPED\r\n");
            }
            
            // Простая задержка антидребезга
            for(int i=0; i<500000; i++);
        }
        btn_prev = btn_curr;
    }
}
```

---

### Лабораторная работа 4: АЦП (Измерение напряжения)
**Задача:** Настройка АЦП и улучшение точности методом усреднения.

#### `init.c`
```c
#include "init.h"

// Настройка USART2 (для вывода данных) - аналогична ЛР 3
void USART2_ini(void) {
    // ... (код идентичен init.c из ЛР 3) ...
    // Для экономии места, скопируйте функцию USART2_ini из ЛР 3
}

// Настройка АЦП (ADC1 на канале 4 - пин PA4)
void ADC_ini(void) {
    ADC_InitTypeDef ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    // 1. Включаем тактирование ADC1 и GPIOA
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    // 2. Настраиваем PA4 как аналоговый вход
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; // Аналоговый режим
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 3. Общие настройки АЦП
    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; // Частота АЦП не должна превышать 36МГц
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    // 4. Настройки ADC1
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; // Один канал
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // Запуск вручную
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    // 5. Включаем ADC1
    ADC_Cmd(ADC1, ENABLE);
}
```

#### `main.c`
```c
#include "main.h"
#include <stdio.h>

#define N_SAMPLES 16 // Число выборок для усреднения

// Функция для printf (такая же, как в ЛР 3)
struct __FILE { int handle; };
FILE __stdout;
int fputc(int ch, FILE *f) {
    USART_SendData(USART2, (uint8_t)ch);
    while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){}
    return ch;
}

void Delay(volatile uint32_t nCount) {
    while(nCount--) {}
}

// Функция чтения и усреднения
uint16_t Get_ADC_Average(void) {
    uint32_t sum = 0;
    
    // Настраиваем канал 4, время выборки 84 цикла
    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_84Cycles);

    for (int i = 0; i < N_SAMPLES; i++) {
        ADC_SoftwareStartConv(ADC1); // Запуск преобразования
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); // Ждем окончания
        sum += ADC_GetConversionValue(ADC1); // Читаем результат
    }
    
    return (uint16_t)(sum / N_SAMPLES);
}

int main(void) {
    USART2_ini();
    ADC_ini();
    
    float voltage;
    uint16_t adc_val;

    while(1) {
        adc_val = Get_ADC_Average();
        // Vref = 3.0V (на Discovery), 12 бит = 4095
        voltage = (float)adc_val * 3.0f / 4095.0f;
        
        printf("ADC: %d, Voltage: %.3f V\r\n", adc_val, voltage);
        
        Delay(5000000); // Пауза
    }
}
```

---

### Лабораторная работа 6: ЦАП + DMA (Генерация сигнала)
**Задача:** Генерация сложного сигнала (две гармоники) через DAC с использованием DMA и Таймера.

#### `init.c`
```c
#include "init.h"

// Настройка GPIO для ЦАП (PA4)
void GPIO_Ini(void) {
    GPIO_InitTypeDef gpio;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
    gpio.GPIO_Pin = GPIO_Pin_4;
    gpio.GPIO_Mode = GPIO_Mode_AN;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &gpio);
}

// Настройка Таймера 2 (Триггер для ЦАП)
void TIM_Ini(void) {
    TIM_TimeBaseInitTypeDef tim;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    tim.TIM_Prescaler = 0; // Максимальная частота
    tim.TIM_CounterMode = TIM_CounterMode_Up;
    tim.TIM_Period = 1000 - 1; // Период срабатывания (частота дискретизации)
    tim.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM2, &tim);
    
    // Таймер генерирует событие TRGO при обновлении
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
    TIM_Cmd(TIM2, ENABLE);
}

// Настройка ЦАП
void DAC_Ini(void) {
    DAC_InitTypeDef dac;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
    
    dac.DAC_Trigger = DAC_Trigger_T2_TRGO; // Запуск от таймера 2
    dac.DAC_WaveGeneration = DAC_WaveGeneration_None;
    dac.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
    
    DAC_Init(DAC_Channel_1, &dac);
    DAC_Cmd(DAC_Channel_1, ENABLE);
    
    // Включаем запрос DMA от ЦАП
    DAC_DMACmd(DAC_Channel_1, ENABLE);
}

// Настройка DMA (Память -> ЦАП)
// buffer - указатель на массив, size - размер массива
void DMA_Ini(uint16_t *buffer, uint32_t size) {
    DMA_InitTypeDef dma;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
    
    DMA_DeInit(DMA1_Stream5); // DAC1 висит на DMA1 Stream 5 Channel 7
    
    dma.DMA_Channel = DMA_Channel_7;
    dma.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR12R1; // Регистр данных ЦАП (12 бит, выравнивание вправо)
    dma.DMA_Memory0BaseAddr = (uint32_t)buffer;
    dma.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    dma.DMA_BufferSize = size;
    dma.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Адрес ЦАП не меняется
    dma.DMA_MemoryInc = DMA_MemoryInc_Enable;          // Адрес массива меняется
    dma.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16 бит
    dma.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    dma.DMA_Mode = DMA_Mode_Circular; // Циклический режим
    dma.DMA_Priority = DMA_Priority_High;
    dma.DMA_FIFOMode = DMA_FIFOMode_Disable;
    dma.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    dma.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    
    DMA_Init(DMA1_Stream5, &dma);
    DMA_Cmd(DMA1_Stream5, ENABLE);
}
```

#### `main.c`
```c
#include "main.h"
#include <math.h>

#define POINTS 100 // Количество точек в периоде
#define PI 3.1415926

uint16_t DualSineWave[POINTS];

// Функция расчета сложной волны (две гармоники)
void Calc_Wave(void) {
    for (int i = 0; i < POINTS; i++) {
        float t = (float)i / POINTS * 2 * PI;
        
        // V = sin(t) + 0.5 * sin(2t)
        // Нормируем результат, чтобы он был от 0 до 4095
        // Исходный диапазон функции от -1.5 до 1.5 (примерно)
        // Смещаем на +1.5 -> диапазон 0..3
        // Умножаем на 4095/3 -> диапазон 0..4095
        
        float val = sin(t) + 0.5 * sin(2 * t);
        
        // Приведение к 12 битам ЦАП
        uint16_t dac_val = (uint16_t)((val + 1.5) * (4095.0 / 3.0));
        
        // Ограничение на всякий случай
        if (dac_val > 4095) dac_val = 4095;
        
        DualSineWave[i] = dac_val;
    }
}

int main(void) {
    Calc_Wave(); // Заполняем массив значениями
    
    GPIO_Ini();
    DMA_Ini(DualSineWave, POINTS); // Настраиваем DMA на наш массив
    DAC_Ini();
    TIM_Ini();  // Запускаем таймер, который начнет "дергать" ЦАП
    
    while(1) {
        // Процессор свободен, генерация идет аппаратно через DMA
    }
}
```
