江科大STM32学习笔记

江科大STM32

资料

STM32 简介





片上资源

系统结构

引脚定义

启动配置

最小系统电路


GPIO

GPIO基本结构

端口位结构






硬件电路的驱动方式

LED闪烁实验

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    while (1)
    {
        GPIO_ResetBits(GPIOA, GPIO_Pin_0);
        Delay_ms(500);
        GPIO_SetBits(GPIOA, GPIO_Pin_0);
        Delay_ms(500);
        
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
        Delay_ms(500);
        
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
        Delay_ms(500);
        GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
        Delay_ms(500);
    }
}

LED流水灯

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    while (1)
    {
        GPIO_Write(GPIOA, ~0x0001);	//0000 0000 0000 0001
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0002);	//0000 0000 0000 0010
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0004);	//0000 0000 0000 0100
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0008);	//0000 0000 0000 1000
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0010);	//0000 0000 0001 0000
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0020);	//0000 0000 0010 0000
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0040);	//0000 0000 0100 0000
        Delay_ms(100);
        GPIO_Write(GPIOA, ~0x0080);	//0000 0000 1000 0000
        Delay_ms(100);
    }
}

蜂鸣器

int main(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    while (1)
    {
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_ResetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(100);
        GPIO_SetBits(GPIOB, GPIO_Pin_12);
        Delay_ms(700);
    }
}

环境搭建

新建工程

工程架构

GPIO输出

GPIO基本结构

GPIO端口位结构

GPIO输入



元器件上拉输入模式在没有输入时默认为低电平

按键控制LED


关键代码

void Key_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
    uint8_t KeyNum = 0;
    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
    {
        Delay_ms(20);
        while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0);
        Delay_ms(20);
        KeyNum = 1;
    }
    if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0)
    {
        Delay_ms(20);
        while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) == 0);
        Delay_ms(20);
        KeyNum = 2;
    }
    
    return KeyNum;
}

光敏传感器控制蜂鸣器

关键代码

void LightSensor_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

uint8_t LightSensor_Get(void)
{
    return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
}

STM32 八种输入输出模式总结

1. GPIO_MODE_AIN 模拟输入

输入信号不经施密特触发器直接接入输入信号为模拟量而非数字量其余输入方式输入数字量

2. GPIO_MODE_IN_FLOATING 浮空输入

输入信号经过施密特触发器接入输入数据存储器当无信号输入时电压不确定因为浮空输入既高阻输入可以认为输入端口阻抗无穷大这样可以检测到微弱的信号相当于电压表测电压如果电压表内阻不够大而外部阻抗比较大则电压表分压会比较小此时输入高电平即高电平输入低电平即低电平但是外界没有输入时输入电平却容易受到外界电磁以及各种玄学干扰的影响如按键采用浮空输入则在按键按下时输入电平为低但是当松开按键时输入端口悬空外界有微弱的干扰都会被端口检测到此时端口可能高也可能低

3. GPIO_MODE_IPD 下拉输入

浮空输入在外界没有输入时状态不确定可能对电路造成干扰为了使得电路更加稳定不出现没有输入时端口的输入数据被干扰 比如手碰一下电压就发生变化这时就需要下拉电阻或上拉电阻,此电阻与端口输入阻抗相比仍然较小有输入信号时端口读取输入信号无输入信号时端口电平被拉到低电平高电平

4. GPIO_MODE_IPU 上拉输入

上拉输入与下拉输入类似只是无输入信号时端口电平被拉到高电平例如按键信号当按下时输入低电平松开时电平被拉到高电平这样就不会出现按键松开时端口电平不确定的情况即不知道时按下还是松开

5. GPIO-MODE_OUT_OD 开漏输出

开漏输出即漏极开路输出这种输出方式指场效应管漏极开路输出需要接上拉电阻才能输出1漏极经上拉电阻接到电源栅极输出0时场效应管截止阻抗无线大电压被分到场效应管上此时输出为1当栅极输出1时场效应管导通输出端口相当于接地此时输出0开漏输出高电平时是由外接电源输出的因此可以实现高于输出端口电压的输出可以实现电平的转换开漏输出可以实现线与功能方法是多个输出共接一个上拉电阻但是漏极开路输出上升沿慢因为上升沿是外接电源对上拉电阻以及外接负载充电当上拉电阻较大或者负载容性较大时时间常数较大充电较慢需要较快反映时可以采用下降沿触发此时没有电阻接入电路的时间常数较小充电较快

6. GPIO_MODE_OUT_PP 推挽输出

推挽输出既可以输出1又可以输出0但是无法调节输出电压因为输出高低电平均为三极管输入端电压此电压在由芯片内部供电无法改变推挽输出任意时刻只有一路工作上图为输出高电平时电路工作状态只有三极管导通电阻无外接电阻因此推挽输出损耗小速度快

7. GPIO_MODE_AF_OD 复用开漏输出

STM32单片机内部有其他的外设比如定时器DAC等复用开漏输出与普通开漏输出区别在于开漏输出输出的是输出数据寄存器中的数据复用开漏输出输出的是来自外设的数据

8. GOIO_MODE_AF_PP 复用推挽输出

复用推挽输出原理与复用开漏输出原理相同

OLED调试驱动

中断系统



NVIC嵌套中断向量控制器

EXTI外部中断


配置外设中断的基本流程:

  1. 配置RCC, 打开涉及的外设时钟
  2. 配置GPIO
  3. 配置AFIO
  4. 配置EXTI
  5. 配置NVIC

AFIO复用IO口

旋转编码器

红外传感器计次

void CountSensor_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
    
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line14;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_Init(&EXTI_InitStructure);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
}

uint16_t CountSensor_Get(void)
{
    return CountSensor_Count;
}

void EXTI15_10_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line14) == SET)
    {
        /*如果出现数据乱跳的现象<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>可再次判断引脚电平<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0)
        {
            CountSensor_Count ++;
        }
        EXTI_ClearITPendingBit(EXTI_Line14);
    }
}

STM32中 中断函数的名字是固定的, 参见start文件中的定义

旋转编码器计次

void Encoder_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
    
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_Init(&EXTI_InitStructure);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_Init(&NVIC_InitStructure);
}

int16_t Encoder_Get(void)
{
    int16_t Temp;
    Temp = Encoder_Count;
    Encoder_Count = 0;
    return Temp;
}

void EXTI0_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line0) == SET)
    {
        /*如果出现数据乱跳的现象<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>可再次判断引脚电平<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
            {
                Encoder_Count --;
            }
        }
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) == SET)
    {
        /*如果出现数据乱跳的现象<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>可再次判断引脚电平<span class="bd-box"><h-char class="bd bd-beg"><h-inner>,</h-inner></h-char></span>以避免抖动*/
        if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
        {
            if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
            {
                Encoder_Count ++;
            }
        }
        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

STM32中 中断函数的名字是固定的, 参见start文件中的定义

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1_2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend

定时器TIM




定时中断

定时器时序



RCC时钟树

定时器定时中断

void Timer_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    
    TIM_InternalClockConfig(TIM2);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
    TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
    TIM_Cmd(TIM2, ENABLE);
}

/*
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
        
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}
*/

定时器外部时钟

用IO口模拟外部时钟源

void Timer_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
    TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
    TIM_Cmd(TIM2, ENABLE);
}

uint16_t Timer_GetCounter(void)
{
    return TIM_GetCounter(TIM2);
}

/*
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
    {
        
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    }
}
*/

TIM输出比较





(相当于把PWM当成通讯协议来用, 舵机里面自带驱动电路)

PWM驱动实验

void PWM_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM2);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;		//PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
    
    TIM_Cmd(TIM2, ENABLE);
}

void PWM_SetCompare1(uint16_t Compare)
{
    TIM_SetCompare1(TIM2, Compare);
}

TIM输入捕获



测频法适合高频, 测周法适合低频, 以中界频率为界




PWMI模式测频率/占空比

void IC_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM3);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    
    TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICFilter = 0xF;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);

    TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
    
    TIM_Cmd(TIM3, ENABLE);
}

uint32_t IC_GetFreq(void)
{
    return 1000000 / (TIM_GetCapture1(TIM3) + 1);
}

uint32_t IC_GetDuty(void)
{
    return (TIM_GetCapture2(TIM3) + 1) * 100 / (TIM_GetCapture1(TIM3) + 1);
}

编码器接口




编码器接口测速

void Encoder_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
        
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
    TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;		//PSC
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
    
    TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_ICStructInit(&TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
    TIM_ICInitStructure.TIM_ICFilter = 0xF;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICFilter = 0xF;
    TIM_ICInit(TIM3, &TIM_ICInitStructure);
    
    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    
    TIM_Cmd(TIM3, ENABLE);
}

int16_t Encoder_Get(void)
{
    int16_t Temp;
    Temp = TIM_GetCounter(TIM3);
    TIM_SetCounter(TIM3, 0);
    return Temp;
}

ADC模数转换



ADC基本结构

输入通道

转换模式

  • 单次转换非扫描模式
  • 连续转换非扫描模式
  • 单次转换扫描模式
  • 连续转换扫描模式

AD单通道

void AD_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    
    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    ADC_Cmd(ADC1, ENABLE);
    
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);
}

uint16_t AD_GetValue(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC1);
}

DMA




高位补零/高位舍弃

DMA数据转运

ADC扫描模式+DMA

存储器映像


DMA工作的条件

  1. 转运计数器大于0
  2. 触发源有触发信号
  3. DMA使能

DMA数据转运

uint16_t MyDMA_Size;

void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{
    MyDMA_Size = Size;
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
    DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = Size;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel1, DISABLE);
}

void MyDMA_Transfer(void)
{
    DMA_Cmd(DMA1_Channel1, DISABLE);
    DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);
    DMA_Cmd(DMA1_Channel1, ENABLE);
    
    while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);
    DMA_ClearFlag(DMA1_FLAG_TC1);
}

DMA+AD多通道

uint16_t AD_Value[4];

void AD_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);
        
    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_NbrOfChannel = 4;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    DMA_InitTypeDef DMA_InitStructure;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 4;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel1, ENABLE);
    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);
    
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1) == SET);
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1) == SET);
    
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

串口通信




USART


串口发送+接收

void Serial_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        
    GPIO_InitTypeDef GPIO_Structure;
    GPIO_Structure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_9;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);
    
    GPIO_Structure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);
    
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_Init(USART1, &USART_InitStructure);
    
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(USART1, ENABLE);
    
}

void Serial_ByteSend(uint8_t byte)
{
    USART_SendData(USART1, byte);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); 
    
}

//printf的移植
void Serial_Printf(char *format, ...)
{
    char String[100];
    va_list arg;
    va_start(arg, format);
    vsprintf(String, format, arg);
    va_end(arg);
    Serial_SendString(String);
}

Hex/文本数据包


数据包接收


串口发送文本数据包

状态机核心代码

void USART1_IRQHandler(void)
{
    static uint8_t RxState = 0;
    static uint8_t pRxPacket = 0;
    if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
    {
        
        uint8_t RxData = USART_ReceiveData(USART1);
        if(RxState == 0)
        {
            if(RxData == '@')
            {
                RxState = 1;
                pRxPacket = 0;
            }
        }
        else if(RxState == 1)
        {
            if(RxData == '\r')
            {
                RxState = 2;
            }
            
            else
            {		
                Serial_RxPacket[pRxPacket] = RxData;
                pRxPacket ++;
            }

        }
        else if(RxState == 2)
        {
            if(RxData == '\n')
            {
                RxState = 0;
                Serial_RxPacket[pRxPacket] = '\0';
                Serial_RxFlag = 1;
            }
        }
        
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

I2C通信

I2C时序单元




I2C时序



MPU6050


软件I2C读写MPU6050

控制电平


//引脚初始化
void MyI2C_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_Structure;
    GPIO_Structure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_Structure);
    
    GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);
}
//控制引脚电平
void MyI2C_W_SCL(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
    Delay_us(10);
}

void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
    Delay_us(10);
}

uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
    Delay_us(10);
    return BitValue;
}

I2C基本时序单元

void MyI2C_Start(void)
{
    //释放SDA 和 SCL
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(1);
    
    //i2c起始逻辑
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(0);

}

void MyI2C_Stop(void)
{
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i = 0;
    for(i=0; i<8; i++)
    {
        MyI2C_W_SDA(Byte & (0x80 >> i));
        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}

uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;
    MyI2C_W_SDA(1);
    for(i=0; i<8; i++)
    {
        MyI2C_W_SCL(1);
        if(MyI2C_R_SDA() == 1) {Byte |= (0x80 >> i);}
        MyI2C_W_SCL(0);
    }
    return Byte;
}

void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);
    MyI2C_W_SCL(1);
    MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    AckBit = MyI2C_R_SDA();
    MyI2C_W_SCL(0);
    return AckBit;
}

I2C时序

void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data)
{
    MyI2C_Start();
    MyI2C_SendByte(MPU6050_ADDR);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddr);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(Data);
    MyI2C_ReceiveAck();
    MyI2C_Stop();
}

uint8_t MPU6050_ReadReg(uint8_t RegAddr)
{
    uint8_t Data;
    
    MyI2C_Start();
    MyI2C_SendByte(MPU6050_ADDR);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(RegAddr);
    MyI2C_ReceiveAck();
    
    MyI2C_Start();
    MyI2C_SendByte(MPU6050_ADDR | 0x01);
    MyI2C_ReceiveAck();
    Data = MyI2C_ReceiveByte();
    MyI2C_SendAck(1);
    MyI2C_Stop();
    
    return Data;
}

MPU6050

void MPU6050_Init(void)
{
    MyI2C_Init();
    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
    MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

uint8_t MPU6050_GetID(void)
{
    return MPU6050_ReadReg(MPU6050_WHO_AM_I);
}


void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,  \
                     int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
    uint16_t DataH, DataL;
    
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);
    *AccX  = (DataH << 8) | (DataL);
    
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);
    *AccY  = (DataH << 8) | (DataL);
    
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);
    *AccZ  = (DataH << 8) | (DataL);
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);
    *GyroX = (DataH << 8) | (DataL);
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);
    *GyroY = (DataH << 8) | (DataL);
    
    DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);
    DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);
    *GyroZ = (DataH << 8) | (DataL);

}

STM32 I2C外设



传送流程

I2C外设实验

硬件部分核心代码业务逻辑层保持不变

void MPU6050_WriteReg(uint8_t RegAddr, uint8_t Data)
{

    I2C_GenerateSTART(I2C2, ENABLE);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
    
    I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
    
    I2C_SendData(I2C2, RegAddr);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);

    I2C_SendData(I2C2, Data);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED) != SUCCESS);

    I2C_GenerateSTOP(I2C2, ENABLE);
}

uint8_t MPU6050_ReadReg(uint8_t RegAddr)
{
    uint8_t Data;

    I2C_GenerateSTART(I2C2, ENABLE);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);
    
    I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Transmitter);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) != SUCCESS);
    
    I2C_SendData(I2C2, RegAddr);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING) != SUCCESS);

    I2C_GenerateSTART(I2C2, ENABLE);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT) != SUCCESS);

    I2C_Send7bitAddress(I2C2, MPU6050_ADDR, I2C_Direction_Receiver);
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) != SUCCESS);
    
    I2C_AcknowledgeConfig(I2C2, DISABLE);
    I2C_GenerateSTOP(I2C2, ENABLE);
    
    while (I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED) != SUCCESS);
    Data = I2C_ReceiveData(I2C2);
    
    return Data;
}

void MPU6050_Init(void)
{
//	MyI2C_Init();
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_Structure;
    GPIO_Structure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);
    
    GPIO_Init(GPIOB, &GPIO_Structure);
    
    I2C_InitTypeDef I2C_InitStructure;
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 50000;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_Init(I2C2, &I2C_InitStructure);
    
    I2C_Cmd(I2C2, ENABLE);

    
    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);
    MPU6050_WriteReg(MPU6050_CONFIG, 0x06);
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

SPI通信

基本时序单元




SPI时序

W25Q64简介

Flash操作事项


SPI软件读写实验

对电平操作的封装

void MySPI_W_SS(uint8_t bitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)bitValue);
}

void MySPI_W_SCK(uint8_t bitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)bitValue);
}

void MySPI_W_MOSI(uint8_t bitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)bitValue);
}

uint8_t MySPI_R_MISO(void)
{
    return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

SPI时序

void MySPI_Start(void)
{
    MySPI_W_SS(0);
}

void MySPI_Stop(void)
{
    MySPI_W_SS(1);
}

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
    uint8_t ByteRecive=0x00;
    
    uint8_t i;
    for(i=0; i<8; i++)
    {
        MySPI_W_MOSI(ByteSend & (0x80 >> i));
        MySPI_W_SCK(1);
        if(MySPI_R_MISO() == 1)
        {
            ByteRecive |= (0x80 >> i);
        }
        MySPI_W_SCK(0);
    }
    
    return ByteRecive;
}

W25Q64操作时序

void W25Q64_Init(void)
{
    MySPI_Init();
}

void W25Q64_ReadID(uint8_t *MID, uint16_t *DID)
{
    MySPI_Start();
    MySPI_SwapByte(W25Q64_JEDEC_ID);
    *MID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
    *DID = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
    *DID <<= 8; 	//*DID = *DID << 8;
    *DID |= MySPI_SwapByte(W25Q64_DUMMY_BYTE);
    MySPI_Stop();
}

void W25Q64_WriteEnable(void)
{
    MySPI_Start();
    MySPI_SwapByte(W25Q64_WRITE_ENABLE);
    MySPI_Stop();
}

void W25Q64_WaitBusy(void)
{
    MySPI_Start();
    MySPI_SwapByte(W25Q64_READ_STATUS_REGISTER_1);
    uint32_t Timeout = 100000;
    while((MySPI_SwapByte(W25Q64_DUMMY_BYTE) & 0x01) == 0x01)
    {
        Timeout --;
        if(Timeout==0) break;
    }
    MySPI_Stop();
}

void W25Q64_PageProgram(uint32_t Address ,uint8_t *DataArray, uint16_t count)
{
    W25Q64_WriteEnable();
    
    MySPI_Start();
    MySPI_SwapByte(W25Q64_PAGE_PROGRAM);
    MySPI_SwapByte(Address>>16);
    MySPI_SwapByte(Address>>8);
    MySPI_SwapByte(Address);
    
    uint16_t i=0;
    for(i=0; i<count; i++)
    {
        MySPI_SwapByte(DataArray[i]);
    }
    MySPI_Stop();
    W25Q64_WaitBusy();
    
}

void W25Q64_SectorErase(uint32_t Address)
{
    W25Q64_WriteEnable();
    
    MySPI_Start();
    MySPI_SwapByte(W25Q64_SECTOR_ERASE_4KB);
    MySPI_SwapByte(Address>>16);
    MySPI_SwapByte(Address>>8);
    MySPI_SwapByte(Address);
    MySPI_Stop();
    
    W25Q64_WaitBusy();
    
}

void W25Q64_ReadData(uint32_t Address, uint8_t *DataArray, uint32_t Count)
{
    uint32_t i;
    MySPI_Start();
    MySPI_SwapByte(W25Q64_READ_DATA);
    MySPI_SwapByte(Address>>16);
    MySPI_SwapByte(Address>>8);
    MySPI_SwapByte(Address);
    for(i=0; i<Count; i++)
    {
        DataArray[i] = MySPI_SwapByte(W25Q64_DUMMY_BYTE);
    }
    MySPI_Stop();
    
}

SPI外设



SPI硬件通信实验

通信逻辑方面不变, 改变的是底层通信的代码, 用硬件电路实现
改变了2个函数MySPI_Init uint8_t MySPI_SwapByte(uint8_t ByteSend) `

void MySPI_W_SS(uint8_t bitValue)
{
    GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)bitValue);
}

void MySPI_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    
    GPIO_InitTypeDef GPIO_Structure;
    GPIO_Structure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_4;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);
    
    GPIO_Structure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);

    GPIO_Structure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Structure.GPIO_Pin = GPIO_Pin_6;
    GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_Structure);
    
    SPI_InitTypeDef SPI_InitStructure;
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
    SPI_InitStructure.SPI_CRCPolynomial = 7;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
    SPI_Init(SPI1, &SPI_InitStructure);
    
    SPI_Cmd(SPI1, ENABLE);
    
    MySPI_W_SS(1);
}

void MySPI_Start(void)
{
    MySPI_W_SS(0);
}

void MySPI_Stop(void)
{
    MySPI_W_SS(1);
}

uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);
    SPI_I2S_SendData(SPI1, ByteSend);
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);
    return SPI_I2S_ReceiveData(SPI1);
}

23Spring_建模复习

UML中九种图的建模元素以及九种模型图的作用画法 (用例图 时序图 状态图为主)

UMLUnified Modeling Language是一种通用的建模语言用于描述和设计软件系统在UML中有九种不同类型的图分别用于不同的建模目的下面分别介绍它们的建模元素和作用

  1. 用例图Use Case Diagram用于描述系统的功能需求和用户角色主要包含用例Use Case参与者Actor和关系Relationship三个建模元素用例图的作用是帮助开发人员和客户之间共同理解系统的功能需求

  2. 活动图Activity Diagram用于描述系统的业务流程和操作流程主要包含活动Activity控制流Control Flow和对象流Object Flow三个建模元素活动图的作用是帮助开发人员和用户之间共同理解系统的业务流程

  3. 类图Class Diagram用于描述系统的类和类之间的关系主要包含类Class接口Interface关系Relationship等建模元素类图的作用是帮助开发人员理解系统的静态结构和对象之间的关系

  4. 对象图Object Diagram用于描述系统中的对象及其之间的关系主要包含对象Object关系Relationship等建模元素对象图的作用是帮助开发人员理解系统中对象的实例化和关系

  5. 时序图Sequence Diagram用于描述系统中对象之间的时间顺序关系主要包含对象Object生命线Lifeline消息Message等建模元素时序图的作用是帮助开发人员理解系统中对象之间的时间顺序关系

  6. 协作图Collaboration Diagram用于描述系统中对象之间的协作关系主要包含对象Object消息Message等建模元素协作图的作用是帮助开发人员理解系统中对象之间的协作关系

  7. 状态图Statechart Diagram用于描述系统中对象的状态和状态之间的转换主要包含状态State转换Transition等建模元素状态图的作用是帮助开发人员理解系统中对象的状态和状态之间的转换

  8. 部署图Deployment Diagram用于描述系统中组件和节点之间的部署关系主要包含节点Node组件Component等建模元素部署图的作用是帮助开发人员理解系统中组件和节点之间的部署关系

  9. 包图Package Diagram用于描述系统的包和包之间的关系主要包含包Package依赖关系Dependency等建模元素包图的作用是帮助开发人员理解系统包之间的关系

用例图类图时序图(画用例图其中某个功能的时序图)

在UML中不同类型的图有不同的画法和符号其中用例图时序图和状态图是比较常用的三种图下面分别介绍它们的画法

  1. 用例图用例图的画法比较简单用椭圆形表示用例用人形图标表示参与者用线条表示关系用例图通常从左侧开始用例向右侧展开参与者位于用例图的左侧或上方
    录音机用例图

  2. 时序图时序图的画法比较复杂需要画出对象的生命线和消息的流向通常从上往下画生命线用竖线表示消息用箭头表示可以用实线虚线等不同类型的线条表示不同类型的消息
    录音机顺序图

  3. 状态图状态图的画法比较简单用圆角矩形表示状态用箭头表示状态之间的转换可以用实心空心等不同类型的箭头表示不同类型的转换状态图通常从上往下画从初始状态开始沿着状态之间的转换路径画出状态图

  4. 类图: UML类图是一种用于表示面向对象程序设计中的类接口关系等元素的图形化表示法 添加关系使用箭头表示类或对象之间的关系例如使用实线箭头表示继承关系使用虚线箭头表示关联关系添加多重性可以在关系箭头上添加多重性符号以表示类或对象之间的关系的多重性例如* 表示多个1 表示一个

什么是用例, 那些图用来详细描述用例

在软件开发中用例Use Case是一种描述系统功能和行为的技术用例描述了系统的各种功能以及这些功能是如何与系统的用户角色和其他系统进行交互的用例通常用于捕捉系统需求和用户需求以便开发人员和系统分析师能够更好地理解系统的功能和行为并在开发过程中进行测试和验证

在UML中用例可以通过用例图Use Case Diagram和详细用例规范Detailed Use Case Specification来表示和描述用例图是一种UML图形表示方法用于描述系统的用例和角色之间的关系用例图通常包括用例角色和系统边界等元素用例规范则是一种文档用于详细描述每个用例的场景前置条件后置条件流程和其他相关信息

除了用例图和用例规范还有其他UML图形表示方法可以用来描述用例例如

  1. 活动图Activity Diagram用于描述用例场景中的活动和流程

  2. 时序图Sequence Diagram用于描述用例场景中的交互和消息传递

  3. 协作图Collaboration Diagram用于描述用例场景中的对象和它们之间的交互

画出录音机的用例图, 顺序图
CPS系统

CPS系统指的是嵌入式计算机系统和物理系统之间的集成它们共同工作以控制监视和优化物理过程如工业自动化智能交通系统智能制造和智能医疗系统等CPS系统通常需要高度可靠性实时性和安全性因此需要采用特殊的设计方法和技术

实时系统

实时系统指的是需要在严格的时间限制内完成任务的计算机系统这些任务需要在特定的时间内产生正确的结果否则可能会对系统的正常运行产生严重影响实时系统可以分为硬实时系统和软实时系统硬实时系统必须在规定的时间内完成任务而软实时系统可以在某些情况下稍微超过规定的时间限制

名词解释
时间约束Timing constraint实时系统的任务具有一定的时间约束截止时间根据截止时间实时系统的实时性分为硬实时软实时硬实时是指应用的时间需求必须得到完全满足否则就造成重大安全事故
发布时间Release Time作业变成为可执行的时间如果所有的工作在系统开始执行时被释放那么就认为没有发布时间
截止时间Deadline工作被要求执行完成的时间如果截止时间是无限的那么工作就没有最后期限绝对截止时间等于发布时间加上相对截止时间
响应时间Response time作业从发布到执行完成的时间长度

及时性timeless:实时系统中动作必须在事件到达或者预期时间到达时开始执行作出响应在动作开始后的某个时刻必须完成,否则就会造成重大安全事故
并发性concurrency是指多个动作顺序链的同时执行
可预测性predictability系统的可预测性就是系统的响应特性所达到的可预知程度
正确性和鲁棒性correctness and robustness正确性表明一个系统总是运行正确鲁棒性表明系统即使在遇到新的情况不在计划中下也是可靠的因此必须警惕死锁竞争以及其他异常情况
实时操作系统特点 及时性可靠性工业控制武器发射等领域

MDA模型驱动开发 (CIV-PIM-PSID概念为主

MDA模型驱动开发Model Driven Architecture是一种软件开发方法它将模型作为软件系统的核心MDA的核心思想是将系统的设计和实现从平台特定的细节中分离出来以便更容易地实现跨平台的开发在MDA中开发人员首先定义系统的抽象模型然后使用模型转换工具将其转换为特定平台的代码这种方法可以提高开发效率和系统可维护性并提高软件的质量和可重用性

MDA 定义了三种模型

  • 计算独立模型Computation-Independent ModelCIM
    描述系统的需求和将在其中使用系统的业务上下文此模型通常描述系统将用于做什么而不描述如何实现系统CIM 通常用业务语言或领域特定语言来表示 用例图
  • 平台独立模型Platform-Independent ModelPIM
    描述如何构造系统而不涉及到用于实现模型的技术此模型不描述用于为特定平台构建解决方案的机制PIM 在由特定平台实现时可能是适当的或者可能适合于多种平台上的实现 类图顺序图
  • 平台特定模型Platform-Specific ModelPSM
    从特定平台的角度描述解决方案其中包括如何实现 CIM 和如何在特定平台上完成该实现的细节 如SpringJSP模型

RM EDF调度机制

ROPES开发流程(需求分析系统设计系统实现)

Rapid Object-Oriented Process Embedded System 用于嵌入式系统的快速面向对象过程

以下过程都建立在系统的模型之上这些过程可以理解为同一模型的不同视图要明白分析设计阶段用到的UML图

  1. 分析(analysis)阶段对所有可能的正确方案的本质特征进行识别

    • 需求分析(requirements analysis)是从客户获取需求及把这些需求组织为容易理解的形式的过程
    • 系统分析(system analysis)要构造定义更为严格的模型并且以这些需求为基础将系统的行为划分为机械组件电子组件和软件组件
    • 对象分析(Object Analysis)要给出重要的对象和类以及它们的主要属性前面的子阶段定义了系统要求具备的行为这些需求由本阶段给出的对象结构予以满足它还包括两个子阶段
      • 结构对象分析(structural object analysis)以类和对象的形式标识对象分解的结构单元同时建立对象分解的组织单元节点和组件以及这些元素之间的内在关系
      • 行为对象分析(behavioral object analysis)为已识别的类定义必要的动态行为模型
  2. 设计(design)则在分析的结果中添加了一些元素这些元素根据对某些判定准则的优化定义了一份特定的解决方案

    • 架构设计(architectural design)能够给出可部署软件系统的大尺度组织分解
    • 机制设计(Mechanistic Design)对对象间的协作具体化
    • 详细设计(detailed design)定义类的结构和并对各个类的内部进行组织
  3. 转化(translation)阶段为设计创建一个可执行的可部署的实现如将UML模型转化成源代码

  4. 测试(testing)要检查转化的结果是否与设计等价并验证具体实现是否满足了分析阶段建立的正确性准则

自动机的事件迁移等内容理解结合实验



MARTE语言的建模思想;

MARTEModeling and Analysis of Real-Time and Embedded systems是UML的一个扩展语言它特别针对实时和嵌入式系统的建模和分析进行了扩展MARTE提供了一组新的建模元素和工具用于描述实时和嵌入式系统的特性和行为如并发时间资源能耗等方面MARTE还为UML提供了一些新的分析方法和工具用于对实时和嵌入式系统进行性能分析可靠性分析功耗分析等

MARTE语言的建模思想主要包括以下几个方面

  1. 面向模型的建模思想

MARTE语言采用基于模型的方法进行系统建模将系统的各个方面都抽象成模型包括功能架构行为时间和资源等每个模型都有其特定的目的和意义并且可以在系统开发的不同阶段使用和分析

  1. 面向实时和嵌入式系统的建模思想

MARTE语言的建模思想是面向实时和嵌入式系统的因此它包括对实时性可靠性安全性资源约束等方面的建模和分析这些方面在实时和嵌入式系统中都是至关重要的因此MARTE语言的建模思想能够帮助开发人员更好地理解和分析系统的实时性能和约束条件

  1. 面向多视图和多层次的建模思想

MARTE语言的建模思想是面向多视图和多层次的它允许开发人员从不同的视角和层次来描述和分析系统这些视图和层次包括功能架构行为时间和资源等可以帮助开发人员更好地理解系统的不同方面并且可以在不同的开发阶段进行使用和分析

  1. 面向分析和仿真的建模思想

MARTE语言的建模思想是面向分析和仿真的它提供了一系列的分析和仿真工具可以对系统的实时性能和资源利用率等方面进行分析和评估这些工具可以帮助开发人员在系统设计的早期阶段发现和解决问题并且可以提高系统的可靠性和效率

总之MARTE语言的建模思想是面向模型实时和嵌入式系统多视图和多层次分析和仿真等方面的它提供了一种统一的框架可以帮助开发人员更好地进行系统级别的建模和分析

MARTE中什么是refinement

在MARTE中Refinement细化指的是从高层次的抽象模型到低层次的更具体的模型的转换过程在这个过程中高层次的抽象模型被逐步细化成更具体更详细的模型以便更好地描述系统的细节和行为

MARTE中的Refinement可以分为两个方面模型细化和执行细化模型细化是指将高层次的模型转换为低层次的模型以描述系统的结构和行为执行细化是指将高层次的执行模型转换为低层次的执行模型以支持系统的实时性和可靠性

在MARTE中Refinement是一个重要的概念它使得开发人员可以在不同的抽象层次上进行建模和分析从而更好地理解和描述系统的行为和性能通过Refinement开发人员可以逐步深入系统的细节从而更好地理解和优化系统的性能和可靠性

SysML与UML语言的区别从语义语法和所面向建模场景方面进行区分

SysML和UML都是基于图形化建模的语言但它们在语义语法和所面向建模场景方面存在一些区别

  1. 语义方面的区别

SysML是一种专门用于系统工程的建模语言它强调对系统的结构行为和性能等方面进行建模SysML包括对系统的需求结构行为和资源等方面的建模而且可以支持多个视图和层次的建模

UML则是一种通用的建模语言主要用于软件系统的建模和设计UML包括对软件系统的需求结构行为交互和状态等方面的建模而且也可以支持多个视图和层次的建模

  1. 语法方面的区别

SysML是基于UML2.0的扩展它保留了UML的核心概念和语法同时还添加了一些新的元素和语法规则SysML中包括了UML的类图活动图状态图序列图等多种图形化表示法并增加了需求图块定义图行为图等特定于系统工程的图

  1. 面向建模场景方面的区别

SysML主要面向系统工程领域支持对系统需求结构行为资源等多个方面进行建模以及进行系统级别的建模和分析SysML常用于建模和设计复杂的物理系统航空航天系统汽车系统医疗设备等

UML则主要面向软件工程领域支持对软件系统的需求结构行为交互和状态等多个方面进行建模以及进行软件级别的建模和分析UML常用于建模和设计软件系统网络应用系统数据库系统等

总之SysML和UML在语义语法和所面向建模场景方面存在一些区别SysML主要面向系统工程领域强调对系统的结构行为和性能等方面进行建模而UML则主要面向软件工程领域强调对软件系统的需求结构行为交互和状态等方面进行建模

描述一下什么是模型驱动开发(MDD)

模型驱动开发Model-Driven DevelopmentMDD是一种软件开发方法它将建模作为主要活动并通过自动生成代码的方式来实现软件开发MDD是基于模型的软件开发方法之一它提供了一种利用模型来描述软件系统的方法从而可以帮助开发人员更好地理解和实现软件系统

在MDD中模型是软件系统的基础它是对系统的结构行为和功能等方面的抽象描述模型通常使用图形化表示法如UMLSysML等来描述包括用例图类图活动图状态图等这些图形化表示法可以帮助开发人员更好地理解和描述软件系统的各个方面

在MDD中模型不仅仅是一个文档或图形而且它是软件开发的中心所有的代码都是通过模型自动生成的开发人员在模型中定义系统的结构行为和功能等方面的信息然后使用模型转换器将模型转换为代码这些代码可以是各种编程语言如JavaC++Python等的代码也可以是配置文件数据库脚本等

MDD的优点包括

  1. 提高开发效率通过模型自动生成代码可以减少手工编写代码的时间和精力从而提高开发效率

  2. 提高代码质量由于代码是通过模型自动生成的因此可以减少代码错误和缺陷从而提高代码质量

  3. 改善软件维护性由于模型是对系统的抽象描述因此可以更好地理解和维护软件系统

总之模型驱动开发是一种基于模型的软件开发方法它将模型作为软件开发的中心通过自动生成代码的方式来实现软件开发从而提高开发效率代码质量和软件维护性

自动机的事件状态迁移等内容理解

自动机是一种用于描述计算过程或系统行为的数学模型它由一组状态和一组转移函数组成每个状态代表系统或计算过程的一种状态每个转移函数描述了从一种状态到另一种状态的转移过程

自动机可以分为两种类型有限自动机和无限自动机有限自动机是指状态有限的自动机而无限自动机则是状态无限的自动机有限自动机通常用于描述具有固定数量的输入和输出的系统而无限自动机通常用于描述具有无限数量输入和输出的系统例如程序或操作系统

在自动机中事件是指输入到系统的信号或数据状态迁移是指自动机从一种状态到另一种状态的转移过程当自动机接收到一个事件时它会根据当前状态和转移函数计算出下一个状态并根据该状态执行相应的操作或输出

在实际应用中自动机常用于模拟计算机程序控制系统通信协议等它们也可以用于验证系统的正确性和安全性以及用于构建人工智能系统和机器学习模型

顺序图的偏序

顺序图是一种UML图用于描述对象之间的交互关系和消息传递顺序在顺序图中对象之间的交互被表示为一系列的消息传递每个消息传递都有一个发送者和一个接收者

顺序图中的偏序是指消息传递之间的先后顺序如果两个消息传递之间存在偏序关系意味着其中一个消息传递必须在另一个消息传递之前发生这种偏序关系可以通过在顺序图中使用垂直的虚线来表示

例如假设有两个对象A和B之间的交互其中A先发送了一条消息给B然后B再发送一条消息给A在顺序图中可以使用两个垂直的虚线表示这两个消息传递之间的偏序关系具体来说第一个虚线表示A发送消息的时间第二个虚线表示B发送消息的时间这种偏序关系可以帮助开发人员更好地理解和描述对象之间的交互顺序从而更好地设计和实现系统

状态迁移时, 动作执行的顺序

在状态迁移时动作的执行顺序可以分为两种情况

  1. 动作在状态迁移之前执行这种情况下动作会在状态迁移之前执行然后才进行状态的迁移这种情况通常称为”动作优先”它意味着动作的执行对状态的迁移是有影响的例如在状态迁移之前可能需要对一些变量进行计算或更新这些计算或更新的结果可能会影响状态的迁移

  2. 动作在状态迁移之后执行这种情况下动作会在状态迁移之后执行这种情况通常称为”状态优先”它意味着状态的迁移对动作的执行是有影响的例如在状态迁移之后可能需要执行一些操作来处理新状态的变化这些操作可能会影响系统的行为或输出

UML profile 用处, 和UML区别

UML Profile是一种UML扩展机制它允许用户自定义UML元素和图形符号以满足特定领域的需求或特定的开发过程UML Profile提供了一种机制使得用户可以在UML中创建新的元素关系图形符号限制和约束等从而扩展UML的能力和适应性UML Profile可以用于各种领域如嵌入式系统Web应用企业架构等

与UML的区别在于UML是一种通用的建模语言它提供了一套标准化的符号和图形表示方法用于描述软件系统的结构和行为UML包括一些基本元素如类对象接口关系活动用例等以及一些图形符号如类图活动图时序图等UML的目标是提供一种通用的建模语言以便开发人员和系统工程师能够更好地理解和描述软件系统的结构和行为

UML Profile则是在UML基础上进行扩展它允许用户自定义UML元素和图形符号以扩展UML的能力和适应性UML Profile提供了一种机制使得用户可以在UML中创建新的元素关系图形符号限制和约束等从而满足特定领域的需求或特定的开发过程因此UML Profile可以看作是UML的一个扩展它提供了更多的建模元素和自定义能力以适应不同的建模需求

描述系统的执行过程 各次实验的理解(三选二)考察查询语言
实验ATM中死锁, 危害

MacOS外接显卡折腾记录

偶然看见外接GPU这种玩法, 我的MacBook也有雷电三接口, 最近正好觉得写VsCode有些小小卡顿, 也不想大费周折换个新电脑, 只想继续使用这个MacBook (强行找需求:0 ), 所以想搞一个外接显卡来玩玩.

我的硬件设备列表:

  • Macbook Pro 2018 13 inch
  • macOS Monterey 12.01
  • Razer Core V1 (RC21-0094)
  • AMD Raedon RX5700

其中的Razer Core 不同于现在正在售的Razer Core X, 它是相当早版本的一个外接显卡, 而外接显卡由于售价原因一直停留小众, 所以在网络上能找到关于它的内容是比较少的, 这也导致了我之后差点踩坑.

eGPU外接显卡

外接显卡最吸引我的一个点就是它能让本来性能很弱但很具有便携性的设备拥有同等台式机的性能, 在保持灵活性优势的同时弥补设备的性能短板.

雷电三外接显卡是一种外置式图形处理器eGPU由Intel和苹果公司联合开发它可以通过Thunderbolt 3接口与苹果电脑或其他兼容设备连接为其提供额外的图形处理能力用户可以将雷电三外接显卡与笔记本电脑超极本或台式电脑等设备配合使用以提高计算机在图形处理方面的性能表现

雷电三外接显卡通常配备独立显卡例如Nvidia或AMD的高性能显卡可以提供比集成显卡更出色的图形性能能够满足一些对图形处理要求较高的应用需求如视频编辑3D建模游戏等

雷电三外接显卡具有插即用的优点不需要安装驱动程序可以实现即插即用同时它的便携性也使得用户可以轻松将其带到不同的地方使用

但由于显卡坞昂贵的售价(主流显卡坞一般在500美元左右), 而且虽然显卡坞可以提供便携式设备的图形升级路径但这并不是一项完美的解决方案显卡坞本身通常是笨重的而且用户需要安装和拆卸显卡这可能不是一项方便的过程 这些原因这种玩法始终属于小众, 但现在支持雷电3/雷电4/USB4的设备越来越多, 若显卡坞之后能够慢慢降价, 这个玩法可能会慢慢流行.

雷电3协议是由英特尔和苹果共同开发的一种高速传输协议主要用于连接外部设备例如外接显卡外置硬盘网络适配器等它基于PCI Express 3.0和Thunderbolt技术具有带宽高速度快延迟低等优点

雷电3协议的最大带宽可达到40Gbps远高于USB 3.1的带宽这意味着可以通过雷电3接口实现快速数据传输和高速图形处理此外雷电3接口还支持Daisy Chain串联功能使得多个外设可以通过单个Thunderbolt 3端口连接到电脑上大大减少了接线混乱的问题

Thunderbolt3/4

雷电3协议是由英特尔和苹果共同开发的一种高速传输协议主要用于连接外部设备例如外接显卡外置硬盘网络适配器等它基于PCI Express 3.0和Thunderbolt技术具有带宽高速度快延迟低等优点

雷电3协议的最大带宽可达到40Gbps远高于USB 3.1的带宽这意味着可以通过雷电3接口实现快速数据传输和高速图形处理此外雷电3接口还支持Daisy Chain串联功能使得多个外设可以通过单个Thunderbolt 3端口连接到电脑上大大减少了接线混乱的问题

值得注意的是, 在雷电3协议的初期, 虽然很多笔记本电脑都具有雷电3接口, 通过USB-C接口实现Thunderbolt 3速度和功能的接口类型它之所以被称为半血雷电3是因为它仅支持Thunderbolt 3的一部分功能而不是完全支持Thunderbolt 3的全部功能, 但Intel10代之后的cpu支持了雷电接口直连CPU, 所以Intel10代之后的设备不会再有半血雷电3接口. 对于MacBook来说, 从2016年的MacBookPro开始, 苹果就支持完整的雷电3接口, 所以外接显卡理论上不会在我的MacBook上表现出太大的性能损失.

现在新型的设备都开始支持Thunderbolt4协议, Thunderbolt 4的最大速度为40Gbps与Thunderbolt 3相同, 但是它支持带宽的动态分配, Thunderbolt4(一般是Intel的CPU)和USB4(一般是AMD的CPU)都是支持向下兼容雷电3的.

显卡与MacOS的兼容性

早在10系列的时候, 苹果就和英伟达闹掰了, 所以现在MacOS几乎是不可能支持较新的N卡了, 可以直接放弃考虑(除非只用BootCamp运行Windows系统使用, 而这显然不符合我的目的), 所以可以直接考虑AMD显卡, 以下是苹果对AMD各个系列的支持性, 也可以在苹果官网查到.

**AMD Radeon RX 68006800 XT 和 6900 XT **

如果你安装了 macOS Big Sur 11.4 或更高版本则可以使用以下基于 AMD Navi RDNA2 架构的图形卡推荐使用的图形卡包括 AMD Radeon RX 6800AMD Radeon RX 6800 XT 和 AMD Radeon RX 6900 XT7

AMD Radeon RX 6600 XT

如果你安装了 macOS Monterey 12.1 或更高版本则支持使用其他 AMD RDNA2 产品推荐使用的图形卡包括 Sapphire Nitro Radeon RX 6600 XT

**AMD Radeon RX 57005700 XT 和 5700 XT 50 周年纪念版 **

如果你安装了 macOS Catalina 10.15.1 或更高版本则可以使用以下基于 AMD Navi RDNA 架构的图形卡推荐使用的图形卡包括 AMD Radeon RX 5700AMD Radeon RX 5700 XT 和 AMD Radeon RX 5700 XT 50 周年纪念版

**AMD Radeon RX Vega 64Vega Frontier Edition Air 和 Radeon Pro WX 9100 **

这些图形卡基于 AMD Vega 64 架构推荐使用的图形卡包括 Sapphire Vega 64AMD Frontier Edition air-cooled 和 AMD Radeon Pro WX 9100

AMD Radeon RX Vega 56

这些图形卡基于 AMD Vega 56 架构推荐使用的图形卡包括 Sapphire Vega 56

AMD Radeon RX 470RX 480RX 570RX 580 和 Radeon Pro WX 7100

这些图形卡基于 AMD Polaris 架构推荐的图形卡包括 Sapphire Pulse 系列和 AMD WX 系列

显卡坞与MacOS的兼容性

现在主流的显卡坞应该是几乎所有笔记本包括Mac在内都支持的了, 但令我意想不到的是, 由于Razer Core 是在2016年TB3刚提出的时候生产的型号, 尚未成熟, 所以适配性较差, 由于它使用了Mac不支持的USB控制器, 导致MacOS无法识别外置显卡坞.

可以参考这个项目来解决兼容性问题:
rgov/Thunderbolt3Unblocker: Enable unsupported Thunderbolt 3 peripherals on macOS (github.com)

需要用到的文件: Thunderbolt3Unblocker

简单介绍和具体步骤如下:

该项目提供了一个内核扩展可以解锁macOS上不受支持的Thunderbolt 3外围设备例如Razer Core

这实现了与KhaosT的TB3启用器相同的目标后者通过在磁盘上修补IOThunderboltFamily来工作此内核扩展在内存中和动态中执行修补程序

请注意IOThunderboltFamily首先认为外围设备不受支持可能是有原因的使用风险自负

  • 安装之前 需要禁用系统完整性保护:
    请在启动期间重新启动并按住 ⌘R 以进入恢复模式选择实用程序→终端并输入命令csrutil enable --without kext && reboot

  • 重启后执行以下命令:

sudo sh -c 'chown -R root:wheel /Library/Extensions/Thunderbolt3Unblocker.kext && \
chmod -R g-w,o-w /Library/Extensions/Thunderbolt3Unblocker.kext && \
kextcache -i / && \
nvram -d t3u-incompatible && \
kextload -b es.govost.ryan.Thunderbolt3Unblocker'
  • 可能需要在系统偏好设置->安全性中允许扩展之后, 如果终端未输出报错, 且原本在系统信息中设备后面的unsupported字样消失, 应该就可以正常识别了
Executing: /usr/bin/kmutil install --volume-root /
kmutil rebuild done
Executing: /usr/bin/kmutil load -b es.govost.ryan.Thunderbolt3Unblocker

TestBench

Geekbench-OpenCL

Geekbench - Metal

BootCamp启动转换

  • 驱动地址 :

后记: 开机时不能识别驱动, 此方案已经弃用