【嵌入式原理与应用】南航嵌入式——实验例程

本文介绍了STM32微控制器在模拟输入输出系统设计中的应用,包括GPIO的配置、中断、定时器、ADC和DAC的初始化。通过示例展示了如何使用GPIO实现按键控制LED闪烁、电位器位置检测、ADC采集电压信号、DAC输出正弦波以及通过DMA发送音乐数据。此外,还涉及了定时器的多种工作模式,如更新定时、PWM输出、比较定时等。
摘要由CSDN通过智能技术生成

实验例子-代码

GPIO实验

例1:GPIO-MOTO实验

image-20220528211855697

​ 当按下KEY1键时,双色红灯闪烁且电机正转,当按下当KEY2键时,双色绿灯闪烁且电机反转,当按下KEY3键时,双色灯灭,电机停止。

#include "stm32f10x_conf.h"

#define KEY1    GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11)
#define KEY2    GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_12)
#define KEY3    GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)
#define IA(x)    ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_8)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_8)))
#define IB(x)    ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_9)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_9)))
#define LEDR(x)   ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_1)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_1)))
#define LEDG(x)   ((x) ? (GPIO_SetBits(GPIOB, GPIO_Pin_2)) : (GPIO_ResetBits(GPIOB, GPIO_Pin_2)))

/*********************************************
*函数名称:void Delayms(void)
*功能说明:简单延时N ms
**********************************************/
void Delayms(uint16_t N)
{
    uint32_t i;
    for (i = 0; i < (8000 * N); i++);
}

/*********************************************
*函数名称:void GPIO_MOTO_Init(void)
*功能说明:初始化GPIO(LED、MOTO、KEY)
**********************************************/
void GPIO_MOTO_Init(void)
{

    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOD, &GPIO_InitStructure);  /*初始化GPIOD端口PD11=KEY1,PD12=KEY2上拉输入,10MHz*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOC, &GPIO_InitStructure);  /*初始化GPIOC端口PC13=KEY3上拉输入,10MHz*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);  /*初始化GPIOD端口PD2、3、4、7 10MHz推挽输出*/

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);  /*初始化GPIOB端口PB1=RED,PB2=GREEN,PB8=IA,PB9=IB 10MHz推挽输出*/

    /*---------初始化状态指示灯灭OFF------------*/
    IA(0);
    IB(0);                    /*  电机停止  */
    LEDR(0);
    LEDG(0);            /*  双色指示灯全灭  */
    GPIO_SetBits(GPIOD, GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_7);/*  4只指示灯灭 */
}

#define  n 200    /*延时时间常数*/

int main(void) {
    u8 KEY = 0;
    SystemInit();            /*系统初始化*/
    GPIO_MOTO_Init();            /*GPIO初始化*/
    while (1) 
    {
        if (KEY1 == 0) KEY = 1;
        if (KEY2 == 0) KEY = 2;
        if (KEY3 == 0) KEY = 3;
        switch (KEY)
        {
            case 1:        /* 电机正转  */
                IA(1);            /*  PB8=IA=1  			*/
                IB(0);            /*  PB9=IB=0  			*/
                LEDR(1);        /*  PB1=1 红灯闪烁 	*/
                Delayms(n);
                LEDR(0);
                Delayms(n);
                LEDG(0);        /*  PB2=1 绿灯灭  */
                break;
            case 2:        /* 电机反转  */
                IA(0);            /*  PB9=IB=1  			*/
                IB(1);            /*  PB8=IA=0  			*/
                LEDR(0);        /*  PB1=0 红灯灭  	*/
                LEDG(1);        /*  PB2=1 绿灯闪烁  */
                Delayms(n);
                LEDG(0);
                Delayms(n);
                break;
            case 3:        /* 电机停止  */
                IA(0);            /*  PB9=IB=0  			*/
                IB(0);            /*  PB8=IA=0  			*/
                LEDR(0);        /*  PB1=0 红灯灭  	*/
                LEDG(0);        /*  PB2=1 绿灯灭  	*/
                break;
        }
    }
}
										 
例2:GPIO简单交互

​ 当按KEY1(PD11)键时,让LED1(PD2)闪烁;当按KEY2(PD12)键时,让LED2(PD3)闪烁;当按KEY3(PC13)键时,让LED3(PD4)闪烁;当按KEY4(PA0)键时,让LED4(PD7)闪烁;当同时按下KEY1和KEY2时,四个LED发光管全亮。

#define LED1(x) ((x)? GPIO_SetBits(GPIOD,(1<<2)) : GPIO_ResetBits(GPIOD,(1<<2)))
#define LED2(x) ((x)? GPIO_SetBits(GPIOD,(1<<3)) : GPIO_ResetBits(GPIOD,(1<<3)))
#define LED3(x) ((x)? GPIO_SetBits(GPIOD,(1<<4)) : GPIO_ResetBits(GPIOD,(1<<4)))
#define LED4(x) ((x)? GPIO_SetBits(GPIOD,(1<<7)) : GPIO_ResetBits(GPIOD,(1<<7)))

#define KEY1 (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11))
#define KEY2 (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_12))
#define KEY3 (GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13))
#define KEY4 (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))

unit16_t key = 0;

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA, ENABLE); 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3  | GPIO_Pin_4  | GPIO_Pin_7 ; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);
    
   /*KEY1(PD11)和KEY2(PD12)引脚配置为上拉输入*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;/*KEY3(PC13)引脚配置为上拉输入*/
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;/*KEY4(PA0)引脚配置为上拉输入*/
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	/*---------初始化状态四个LED全OFF------------*/
	LED1(1);
	LED2(1);
	LED3(1);
	LED4(1);		
}

void main()
{
	SystemInit();
	GPIO_Configuration();
	while(1)
	{
		if(KEY1 == 0) key = 1;
		if(KEY2 == 0) key = 2;
		if(KEY3 == 0) key = 3;
		if(KEY4 == 0) key = 4;
		if(KEY1 == 0 && KEY2 == 0) key = 5;
		
		switch(key)
		{
			case 1:
				LED2(1); LED3(1); LED4(1);
				LED1(1); Delay(); LED1(0); break;
			case 2:
				LED1(1); LED3(1); LED4(1);
				LED2(1); Delay(); LED2(0); break;
			case 3:
				LED1(1); LED2(1); LED4(1);
				LED3(1); Delay(); LED3(0); break;
			case 4:
				LED2(1); LED3(1); LED4(1);
				LED1(1); Delay(); LED1(0); break;
			case 5:
				LED1(0); LED2(0); LED3(0); LED4(0);
			    break;
			default:
				LED1(1); LED2(1); LED3(1); LED4(1);
				break;
		}
	}
}
例3:GPIO 引脚中断

​ 采用中断方式判断单个按键:当按下KEY1(PD11)时,让LED1(PD2)闪烁;当按下KEY2(PD12)时让LED2(PD3)闪烁;采用查询方式判断复合键:当同时按下KEY1和KEY2时,LED1和LED2发光管全灭。

#define LED1(x) ((x)? GPIO_SetBits(GPIOD,(1<<2)) : GPIO_ResetBits(GPIOD,(1<<2)))
#define LED2(x) ((x)? GPIO_SetBits(GPIOD,(1<<3)) : GPIO_ResetBits(GPIOD,(1<<3)))

#define KEY1 (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11))
#define KEY2 (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_12))

unit16_t Flag = 0;

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO, ENABLE); 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 ; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11|GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOD , GPIO_PinSource11);/*PD11作为外部中断线*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOD , GPIO_PinSource12);/*PD12作为外部中断线*/
	
	/*---------初始化状态2个LED全OFF------------*/
	LED1(1);
	LED2(1);		
}

void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	     /*使用优先级分组2*/
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn ;/*配置EXTI第15~10线的中断向量*/ 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0 ;/*抢占优先级0*/
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	  /*子优先级1*/
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE ;	
	NVIC_Init(&NVIC_InitStructure);
}

void EXTI_Configuration(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line11;  	/*PD11外部中断输入*/
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	/*下降沿触发*/
	EXTI_InitStructure.EXTI_LineCmd	= ENABLE;
	EXTI_Init(&EXTI_InitStructure);	
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line12;  /*PD12外部中断输入*/
	EXTI_Init(&EXTI_InitStructure);	
}

void EXTI15_10_IRQHandler() /* 中断服务程序 */
{
	if(EXTI_GetITStatus(EXTI_Line11) != RESET)
	{
		Flag = 0x01;
		EXTI_ClearITPendingBit(EXTI_Line11);
	} 
	else if(EXTI_GetITStatus(EXTI_Line12) != RESET)
	     {
		    Flag = 0x2;
		    EXTI_ClearITPendingBit(EXTI_Line12);
	     }
}


int main()
{
	SytemInit();
	GPIO_Configuration();
	NVIC_Configuration();
	EXTI_Configuration();
	while(1)
	{
		if(KEY1 == 0 && KEY2 == 0)
		{
			Flag = 0x03;
		}
		
		switch(Flag)
		{
			case 0x01:
				LED2(1);
				LED1(0); Delay(); LED1(1); Delay();
				break;
			case 0x02:
				LED1(1); 
				LED2(0); Delay(); LED2(1); Delay();
				break;
			case 0x03:
				LED1(1); LED2(1);
				break;
			default:
				LED1(0); LED2(0);
				break;
		}
	}
}

TIM实验

例1:TIM更新方式定时

​ 定时器TIM1定时1秒,TIM2定时500ms,TIM3定时200ms,定时器到时分别使LED1、LED2和LED3改变状态(闪烁)

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);
	GPIO_InitStructure.GPIO_Pin = LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = LED5_PIN;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = BEEP_PIN ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/*---------初始化状态四个LED全OFF------------*/
	LED1(1);
	LED2(1);
	LED3(1);
	LED4(1);
			
}
void NVIC_Configuration(void)
{
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* Set the Vector Table base location at 0x08000000 */
	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);  	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}

void TIM_Configuration(void)
{

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
							 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);/*使能TIM1时钟,因为TIM1和TIM8连接在APB2上*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM3, ENABLE);/*使能TIM2/TIM3时钟,因为TIM2~TIM7连接在APB1上*/

	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0	;/*不能少!对于TIM1/TIM8高级定时器必须把重新计数清零,否则TIM1定时器不准确,利用它可以重新不同的定时次数达到不同定时*/
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 10*1000-1; //1000ms
	TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/10000-1;//0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 10*500-1; //500ms
	TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/10000-1;//0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;	
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 10*200-1; //200ms
	TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/10000-1;//0;
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	
	/* TIM Interrupts enable */
	TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	
	/* TIM1/2/3 enable counter */
	TIM_Cmd(TIM1, ENABLE);
	TIM_Cmd(TIM2, ENABLE);
	TIM_Cmd(TIM3, ENABLE);
}

u8 TP1=0,TP2=0,TP3=0;

void TIM1_UP_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)  /*判断是否是更新中断*/
	{
		TIM_ClearITPendingBit(TIM1, TIM_IT_Update);       /*清除中断标志*/
		TP1++;
		if (TP1&1) 			GPIO_ResetBits(GPIOD,GPIO_Pin_2);   /*  PD2=0(LED1亮)*/
		else 				GPIO_SetBits(GPIOD,GPIO_Pin_2); 		/*  PD2=1(LED1灭)*/
	}
}
void TIM2_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) 	/*判断是否是更新中断*/
	{
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update); 			/*清除中断标志*/
		TP2++;
		if (TP2&1) 			GPIO_ResetBits(GPIOD,GPIO_Pin_3);   /*  PD3=0(LED2亮)*/
		else 				GPIO_SetBits(GPIOD,GPIO_Pin_3); 		/*  PD3=1(LED2灭)*/
	}
}
void TIM3_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  /*判断是否是更新中断*/
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);       /*清除中断标志*/
		TP3++;
		if (TP3&1) 			GPIO_ResetBits(GPIOD,GPIO_Pin_4);   /*  PD4=0(LED3亮)*/
		else 				GPIO_SetBits(GPIOD,GPIO_Pin_4); 		/*  PD4=1(LED3灭)*/
	}
}

int main(void)
{
	SystemInit();
	GPIO_Configuration();
	TIM_Configuration();         			/*  初始化TIMx定时器  */
	NVIC_Configuration();	
	LCD_Init();												/*  LCD初始化        */
	Welcome(); 										 		/*  显示主界面       */
	LED1(1);LED2(1);LED3(1);LED4(1);
	while(1)
	{		
		/*  本例程,主循环体不做事情,全部在中断函数中让LED闪烁,可根据需要自行加功能代码*/
	}
}
例2:TIM比较定时

​ 定时器TIM3利用比较器1定时1秒让LED1闪烁,比较器2定时500ms,让LED2闪烁,比较器3定时200ms,让LED3闪烁,比较器4定时100ms让LED4闪烁

u16 CCR1_Val = 10*1000;	/*定时1000ms*/
u16 CCR2_Val = 10*500;	/*定时500ms*/
u16 CCR3_Val = 10*200;	/*定时200ms*/
u16 CCR4_Val = 10*100;	/*定时100ms*/

void TIM_Configuration(void)
{

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
								 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period =65535;
	TIM_TimeBaseStructure.TIM_Prescaler =(SystemCoreClock/10000)-1;/*预分频*/
	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
		
	/* Output Compare Timing Mode configuration: Channel1 */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;						/*输出定时模式*/
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;/*输出禁止,这里仅比较,不输出*/
	TIM_OCInitStructure.TIM_Pulse = CCR1_Val;											/*比较脉冲个数*/
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	
	
	/* Output Compare Timing Mode configuration: Channel2 */
	TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	
	/* Output Compare Timing Mode configuration: Channel3 */
	TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
	TIM_OC3Init(TIM3, &TIM_OCInitStructure);
	
	//TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
	TIM_OC4Init(TIM3, &TIM_OCInitStructure);
	
	
	
	/* TIM Interrupts enable */
	TIM_ITConfig(TIM3, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 |TIM_IT_CC4, ENABLE);
	
	/* TIM3 enable counter */
	TIM_Cmd(TIM3, ENABLE);
}

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD, ENABLE);
	GPIO_InitStructure.GPIO_Pin = LED1_PIN | LED2_PIN | LED3_PIN | LED4_PIN ;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = LED5_PIN;
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = BEEP_PIN ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/*---------初始化状态四个LED全OFF------------*/
	LED1(1);
	LED2(1);
	LED3(1);
	LED4(1);
			
}

void NVIC_Configuration(void)
{
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* Set the Vector Table base location at 0x08000000 */
	NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);  	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
}

extern u16 CCR1_Val;
extern u16 CCR2_Val;
extern u16 CCR3_Val;
extern u16 CCR4_Val;

void TIM3_IRQHandler(void)
{
	uint16_t capture = 0;
	if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);		/*是比较中断,清除中断标志*/
		
   			GPIOD->ODR ^= 1<<2;											/*LED1(PD2)*/
		capture = TIM_GetCapture1(TIM3);						/*取当前计数值*/
		TIM_SetCompare1(TIM3, capture + CCR1_Val);	/*写新比较值到比较寄存器*/
	}
	else if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
		
   			GPIOD->ODR ^= 1<<3;	/*LED2(PD3)*/
		capture = TIM_GetCapture2(TIM3);
		TIM_SetCompare2(TIM3, capture + CCR2_Val);
	}
	else if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC3);
		
   			GPIOD->ODR ^= 1<<4;	/*LED3(PD4)*/
		capture = TIM_GetCapture3(TIM3);
		TIM_SetCompare3(TIM3, capture + CCR3_Val);						   
	}
	else if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
		
   			GPIOD->ODR ^= 1<<7;	/*LED4(PD7)*/
		capture = TIM_GetCapture4(TIM3);
		TIM_SetCompare4(TIM3, capture + CCR4_Val);						   
	}
	
}

int main(void)
{
	SystemInit();
	GPIO_Configuration();
	TIM_Configuration();         			/*  初始化TIMx定时器  */
	NVIC_Configuration();	
	LCD_Init();												/*  LCD初始化        */
	Welcome(); 										 		/*  显示主界面       */
	LED1(1);LED2(1);LED3(1);LED4(1);
	while(1)
	{		
		/*  本例程,主循环体不做事情,全部在中断函数中让LED闪烁,可根据需要自行加功能代码*/
	}
}
例3:输出PWM波

​ 运行程序后PWM输出频率10kHz,起始占空比50%

void Init_TIMER(void)
{
	TIM_TimeBaseInitTypeDef	 TIM_BaseInitStructure;				//定义一个定时器结构体变量
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  //使能定时器4,重要!!
	TIM_DeInit(TIM4);                              				//将IM2定时器初始化位复位值
	TIM_InternalClockConfig(TIM4); 												//配置 TIM4 内部时	   
	TIM_BaseInitStructure.TIM_Period = 7200-1; 						//设置自动重载寄存器值为最大值	0~65535之间  7200/72000000=1/10000s=0.1ms即10KHz													
															//TIM_Period(TIM1_ARR)=7200,计数器向上计数到7200后产生更新事件,
															//计数值归零 也就是 1ms产生更新事件一次
	TIM_BaseInitStructure.TIM_Prescaler = 0;  				//自定义预分频系数为0,即定时器的时钟频率为72M提供给定时器的时钟	0~65535之间
															//设置预分频器分频系数0
	TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割为0
	TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;   
															//TIM向上计数模式 从0开始向上计数,计数到1000后产生更新事件
	TIM_TimeBaseInit(TIM4, &TIM_BaseInitStructure); 		//根据指定参数初始化TIM时间基数寄存器	
      
 	TIM_ARRPreloadConfig(TIM4, ENABLE);						//使能TIMx在 ARR 上的预装载寄存器 

	TIM_Cmd(TIM4, ENABLE); 		          //使能TIM4
}

void Init_PWM(uint16_t Dutyfactor)
{
	TIM_OCInitTypeDef  TIM_OCInitStructure;					//定义一个通道输出结构

	TIM_OCStructInit(&TIM_OCInitStructure);					//设置缺省值

	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;	   	//PWM 模式 1 输出 	
	TIM_OCInitStructure.TIM_Pulse = Dutyfactor; 			//设置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%
															  
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//TIM 输出比较极性高   
																    
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    	//使能输出状态  需要PWM输出才需要这行代码
														
  TIM_OC3Init(TIM4, &TIM_OCInitStructure);				//根据参数初始化PWM寄存器 通道3(PB8)   

	TIM_OC3PreloadConfig(TIM4,TIM_OCPreload_Enable);//使能 TIMx在 CCR3 上的预装载寄存器

  TIM_CtrlPWMOutputs(TIM4,ENABLE);  							//设置TIM4 的PWM 输出为使能  
}

void PWM_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;					//定义一个GPIO结构体变量

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);	
																								//使能各个端口时钟
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8| GPIO_Pin_9; //PB8和PB9引脚,PB6、PB7、PB8和PB9分别为TIM4对应的CH1、CH2、CH3和CH4四个通道的PWM输出引脚,这里使用PB8和PB9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	   	  //复用输出推挽
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	   	//配置端口速度为50M
	GPIO_Init(GPIOB, &GPIO_InitStructure);				   			//将端口GPIOD进行初始化配置
}

int main(void)
 {	
	 
	uint16_t Pulse=7200*0.5;				//占空比为50%  周期7200(1ms)
	SystemInit();
	PWM_GPIO_Init();		    		//PWM输出口PB8,初始化
	Init_TIMER();								//定时器4初始化
	Init_PWM(Pulse);			  //PWM的通道3初始化设置	
	GPIO_Configuration();
	TIM2_Cap_Init(0xffff,72-1);					/*以1MHz的频率计数,初始化TIM2定时器  */
	LCD_Init();													/*  LCD初始化        */
	Welcome(); 										 			/*  显示主界面       */
	LED1(1);LED2(1);LED3(1);LED4(1);
	while(1)
	{		
 		if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_11)==0)   //KEY1按下
		{
			Pulse+=100;									   //占空比加100
			if(Pulse>=7200-1) Pulse=1;
			TIM_SetCompare3(TIM4,Pulse);                   //写入定时器4的通道3的占空比值
		}
	
		
		if(GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12)==0)   //KEY2按下
		{
			Pulse-=100;									   //占空比减100
			if((Pulse<1)||(Pulse>7200))   Pulse=7200-1;
			TIM_SetCompare3(TIM4,Pulse);                   //写入定时器4的通道3的占空比值
		}
			Delay_ms(100);
			LCD_ShowNum(80,190,Pulse,8,16);		/*显示总的脉冲个数*/
			LCD_ShowNum(80,230,Pulse*100/7200,8,16);	/*显示总的脉冲个数*/

	}
}
例4:按键时长判断

​ 利用定时计数器TIM3定时 10ms,每当 10ms 中断一次,在中断服务程序中判断按键,当按键按下超过 0.5 秒小于 1 秒时称为短按,按下超过 3 秒时为长按。

试用 C 语言写出定时器 TIM3定时 10ms 的初始化函数:

(1)当短按奇数次按键时,让 LED 发光,短按偶数按键时,让 LED 熄灭;

(2)长按偶数次按键时让蜂鸣器发声报警,长按奇数次按键时停止发声。

void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_SetVecorTable(NVIC_VecTab_FLASH,0x0000);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC, ENABLE); 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	
	/*---------初始化状态LED OFF------------*/
	LED1(1);		
}

void TIM_Configuration(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	TIM_TimeBaseStructure.TIM_Period=10*10-1;
	TIM_TimeBaseStructure.TIM_Prescaler=SystemCoreClock/10000-1;
	TIM_TimeBaseStructure.TIM_ClockDivision=0;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	TIM_Cmd(TIM3,ENABLE);
}

#define ShortKeyConst 50
#define LongKeyConst 300

u32 TP1=0, TP2=0, Times;

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update)!=RESET)
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
		if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == 0) Times++;
		else{
			if(Times >= LongKeyConst)
			{
				TP1++;
				if(TP1&1 == 1) GPIO_SetBits(GPIOC,GPIO_Pin_0);
				else GPIO_ResetBits(GPIOC,GPIO_Pin_4);
			}
			else if((Times >= ShortKeyConst) && (Times <= ShortKeyConst*2))
				 {
					TP2++;
					if(TP2&1 == 1) GPIO_SetBits(GPIOD,GPIO_Pin_2);
					else GPIO_ResetBits(GPIOD,GPIO_Pin_2);
				 }
			Times = 0; 
		}
	}
}

int main(void)
{
	SystemInit();
	GPIO_Configuration();
	TIM_Configuration();
	NVIC_Configuration();
	LCD_Init();
	Welcome();
	LED1(1);LED2(1);LED(3);LED(4);
	while(1)
	{
		
	}
} 

模拟输入输出系统设计

例1:ADC应用

​ 对于 STM32F10x 微控制器,使用片上 ADC 通道 3(PA3 作为 ADCIN3)作为电位器位置检测的一个实例,如图 7.41 所示。当旋转电位器 VR1 时,ADCIN3 随之电压发生变化,如果电位代表位置,假设 0V表示位置 0 米,3.3V 表示 100 米,当电位器从最低端向最高端旋转时,电位从 0 到 3.3V 变化,也即位置从 0 到 100 米线性变化。试回答:

image-20220528212021085

(1)写出对片上 DAC 的初始化程序片段(含引脚配置及 DAC 初始化)。

(2)写出采集电位并进行标度变换的程序。

void ADC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_ADC1,ENABLE);/*PA3 为 ADCIN3*/		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                   /*管脚频率50MHz*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	                    	/*模拟输入模式*/
	GPIO_Init(GPIOA, &GPIO_InitStructure);

/* 初始化ADC:独立模式、多通道扫描、连续转换、软件触发、ADC数据右对齐 */			
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	                /*独立工作模式*/
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;					    /*禁止多通道扫描*/
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;				/*连续转换模式禁止*/
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	/*不用外部触发,用软件触发启动*/
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	    /*ADC数据右对齐*/
	ADC_InitStructure.ADC_NbrOfChannel = 1; /*进行规则转换的ADC通道数为1个通道(ADCIN3)*/
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);	                     /*使能ADC1*/
	ADC_ResetCalibration(ADC1);	                 /*使能ADC1复位校准寄存器*/
	while(ADC_GetResetCalibrationStatus(ADC1));	 /*等待复位校准寄存器接收*/
	ADC_StartCalibration(ADC1);			         		 /*启动ADC1校准*/
	while(ADC_GetCalibrationStatus(ADC1));	     /*等待ADC1校准结束*/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		 	 /*启动软件转换*/
}

int Read_ADC1_MultiChannel(u8 channNo)
{  
	u16  ADC_data;
    ADC_RegularChannelConfig(ADC1, channNo, 1, ADC_SampleTime_239Cycles5 );/* 设置指定channNo通道及采样率*/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		 		/*使能ADC1 */
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));	/*等待AD转换结束*/
    ADC_data=ADC_GetConversionValue(ADC1);  		  /*取AD转换结果*/
    ADC_SoftwareStartConvCmd(ADC1, DISABLE);	 		/*关闭ADC1*/
return(ADC_data);                             /*返回转换结果*/                                        
} 

int main()
{
	int value = 0;
	int voltage = 0; 
	int dis = 0;
	ADC_Configuration ();
	while(1)
	{
		value = Read_ADC1_MutiChannel(ADC_Channel_3);
		voltage = (3300*value)/4095;  // 标度转换后的电压值,单位mv 
		dis = (100*value)/4095;    // 标度转换后的距离 
	}
} 
例2:ADC_DAC应用

​ 试设计一个模拟输入输出系统,采用 STM32F10x 微控制器,采用 3.3V 供电,内置 12 位 ADC,某压力传感器输出 0-100mV 对于 0-10Mpa,压力超过 8.5Mpa 时,输出报警信号,让蜂鸣器发声,低于 8Mpa时解除报警。并将得到的压力用 4-20mA 电流输出到外部。写出相关程序片段。

image-20220528212100863

image-20220528212104778

image-20220528212128861

void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIO_ResetBit(GPIOC,GPIO_Pin_0);  // 初始化蜂鸣器不响		
}

void ADC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO|RCC_APB2Periph_ADC1,ENABLE);/*PA1 为 ADCIN1*/		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                   /*管脚频率50MHz*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	                    	/*模拟输入模式*/
	GPIO_Init(GPIOA, &GPIO_InitStructure);

/* 初始化ADC:独立模式、多通道扫描、连续转换、软件触发、ADC数据右对齐 */			
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	                /*独立工作模式*/
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;					    /*禁止多通道扫描*/
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;				/*连续转换模式禁止*/
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	/*不用外部触发,用软件触发启动*/
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	            /*ADC数据右对齐*/
	ADC_InitStructure.ADC_NbrOfChannel = 1; /*进行规则转换的ADC通道数为1个通道(ADCIN1)*/
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);	                     /*使能ADC1*/
	ADC_ResetCalibration(ADC1);	                 /*使能ADC1复位校准寄存器*/
	while(ADC_GetResetCalibrationStatus(ADC1));	 /*等待复位校准寄存器接收*/
	ADC_StartCalibration(ADC1);			         		 /*启动ADC1校准*/
	while(ADC_GetCalibrationStatus(ADC1));	     /*等待ADC1校准结束*/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		 	 /*启动软件转换*/
}

void DAC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE );	 //使能PORTA通道时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );	  //使能DAC通道时钟 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 		 //复用推挽(模拟)输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	DAC_DeInit();
	
	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能   DAC_Trigger_T3_TRGO 定时器为触发源 
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
    DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
	DAC_SetChannel1Data(DAC_Align_12b_R, 0x0);  //12位右对齐数据格式设置DAC初始值,输出0
}

int Read_ADC1_MultiChannel(u8 channNo)
{  
	u16  ADC_data;
    ADC_RegularChannelConfig(ADC1, channNo, 1, ADC_SampleTime_239Cycles5 );/* 设置指定channNo通道及采样率*/
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		 		/*使能ADC1 */
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));	/*等待AD转换结束*/
    ADC_data=ADC_GetConversionValue(ADC1);  		  /*取AD转换结果*/
    ADC_SoftwareStartConvCmd(ADC1, DISABLE);	 		/*关闭ADC1*/
	return(ADC_data);                             /*返回转换结果*/                                        
} 

int main()
{
   int high = 4095 * 8.5 / 10;
   int low = 4095 * 8.0 / 10;
   int Din
   SystemInit();
   GPIO_Configuration();
   ADC_Configuration();
   DAC_Configuration();
   while(1)
   {
   	   Din = Read_ADC1_MultiChannel(ADC_Channel_1);
   	   if(Din > high) GPIO_SetBit(GPIOC, GPIO_Pin_0); // 报警 
   	   else if(Din < low) GPIO_ReSetbits(GPIOC, GPIO_Pin_0); // 解除报警
	
	   Dout = 496 + (1986 * Din) / 4095;
	   DAC_SetChannel1Data(DAC_Align_12b_R, Dout); // 输出电流 
   } 	
}
例3:ADC_DMA应用
void GPIO_Configuration()
{ // 将用到的引脚配置为模拟输入模式
    GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);		
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6 | GPIO_Pin_7;   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        /*管脚频率50MHz*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	              /*模拟输入模式*/
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
}

void DMA_Congiguration(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA1时钟
	
	DMA_DeInit(DMA1_Channel1);  //指定DMA通道
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC_DR_Address;//设置DMA外设地址ADC_DR_Adress
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;	//设置DMA内存地址,ADC转换结果直接放入该地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设为设置为数据传输的来源
    DMA_InitStructure.DMA_BufferSize = SampleNum*ChannelNum;	//DMA缓冲区设置
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//DMA不允许地址递增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存地址递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);	
    DMA_Cmd(DMA1_Channel1, ENABLE);  //使能DMA通道
}

void ADC_Configuration(void)
{
  DMA_Congiguration();    // ADC的DMA初始化 
  
  ADC_InitTypeDef ADC_InitStructure;	
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//使能ADC1时钟
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //使用独立模式
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;			 //扫描模式允许,多通道必须使能
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连接转换模式,无需外接触发器
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不用外部触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //使用数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = ChannelNum;  // ChannelNum个通道转换通道
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_55Cycles5); //通道3(电位器)采样周期55.5个时钟周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 2, ADC_SampleTime_55Cycles5); //通道6(PT100)采样周期55.5个时钟周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 3, ADC_SampleTime_55Cycles5); //通道7(电流电压)采样周期55.5个时钟周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 4, ADC_SampleTime_55Cycles5); //通道16(内部温度)采样周期55.5个时钟周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 5, ADC_SampleTime_55Cycles5); //通道17(基准电压)采样周期55.5个时钟周期

  ADC_DMACmd(ADC1, ENABLE);	 //使能ADC的DMA
  ADC_Cmd(ADC1, ENABLE); //使能ADC1
  ADC_TempSensorVrefintCmd(ENABLE);			 					 /*使能温度传感器和内部参考电压通道*/	

  ADC_ResetCalibration(ADC1);
  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1));
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);  //开始转换
}

int ReadADCAverageValue(uint16_t Channel)  //求平均值
{
 	u8 i;
 	u32 sum = 0;
 	for(i=0; i<SampleNum; i++)
 	{
  		sum+=ADC_ConvertedValue[i][Channel];
 	}
 	return (sum/SampleNum);
}

int main()
{
   SystemInit();
   GPIO_Configuration();
   ADC_Configuration();
   while(1)
   {
   	   int value0 =  ReadADCAverageValue(0);
   	   int value1 =  ReadADCAverageValue(1);
   	   int value2 =  ReadADCAverageValue(2);
   	   int value3 =  ReadADCAverageValue(3);
   	   int value4 =  ReadADCAverageValue(4);
   	   // ......
   }
} 
例4:DAC输出频率为f的正弦波
int index = 0;

const uint16_t Sine12bit[32] = {2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4096, 4056,
								3939, 3750, 3459, 3185, 2831, 2447, 2047, 1647, 1263, 909,
								599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};
								
void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_SetVecorTable(NVIC_VecTab_FLASH,0x0000);
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

void TIM_Configuration(uint16_t f)
{
	TIM_TimeBaseInitTypeDef	TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE);
	TIM_DeInit(TIM3);
	TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/1/32/f-1;//一个周期32个点,两间隔离时间的倒数即频率,改变这个值能改变正弦波的频率 反比例变化    
	TIM_TimeBaseStructure.TIM_Prescaler = 0x0;       //这个值要为零 否则无输出   	 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;   //这个值要为零 否则无输出
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);	
	TIM_Cmd(TIM3, ENABLE);	   //使能TIM3
}

void DAC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE );	  //使能PORTA通道时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );	  //使能DAC通道时钟 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 // 端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 		 //复用推挽(模拟)输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	DAC_DeInit();
	
	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能   
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
     DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
	DAC_SetChannel1Data(DAC_Align_12b_R, 0x0);  //12位右对齐数据格式设置DAC初始值,输出0
}

void TIM3_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  /*判断是否是更新中断*/
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update);       /*清除中断标志*/
	    DAC_SetChannel1Data(DAC_Align_12b_R, uint16_t Sine12bit[index++]);
	    if(index >= 32) index = 0;
	}
}

int main()
{
	NVIC_Configuration();
	TIM_Configuration(f);
	DAC_Configuration();
	// ......
}
例5:DAC_DMA输出乐曲
uint32_t DAC_DHR12R2_Address = 0x40007414;	  //0x4000 7400 - 0x4000 77FF为DAC地址范围,其中0x40007414为DAC2右对齐数据保持寄存器
const uint16_t Sine12bit[32] = {   /*32正弦波点*/
                      2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
                      3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 
                      599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};

uint32_t DAC2Sine12bit[32];
const uint16_t Redfrebit[]={......}  //存放音乐的频率 
void TIM_Configuration(uint16_t f)
{
	TIM_TimeBaseInitTypeDef	TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,ENABLE);
	TIM_DeInit(TIM3);
	TIM_TimeBaseStructure.TIM_Period = SystemCoreClock/1/32/f-1;//一个周期32个点,两间隔离时间的倒数即频率,改变这个值能改变正弦波的频率 反比例变化    
	TIM_TimeBaseStructure.TIM_Prescaler = 0x0;       //这个值要为零 否则无输出   	 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;   //这个值要为零 否则无输出
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);  //使用更新事件作为触发输出	
	TIM_Cmd(TIM3, ENABLE);	   //使能TIM3
}

void DAC_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC ,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);		   

	/*-----------DAC端口配置 复用输出模式-------------*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	 //PA5:DAC2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA ,&GPIO_InitStructure);
	DAC_DeInit();									  //还原到初始状态

	/* DAC 通道2配置 */
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T3_TRGO;	//选择定时器3作外部触发源
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;	   //自定义波形产生
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;	   //失能输出缓冲
	DAC_Init(DAC_Channel_2, &DAC_InitStructure);					   //DAC初始化
	DAC_Cmd(DAC_Channel_2,  ENABLE);								   //使能DAC
	DAC_SoftwareTriggerCmd(DAC_Channel_2, ENABLE);					   //通道2由软件触发	
}

void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2 ,ENABLE);				 //打开DMA2时钟
	DMA_DeInit(DMA2_Channel4);								         //将DMA通道4 的寄存器设为默认值
	DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12R2_Address;	 //DAC2  12位右对齐数据寄存器地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DAC2Sine12bit; //待送入DAC2的数字量
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;				 //外设作为数据传输的来源
	DMA_InitStructure.DMA_BufferSize = 32;						     //DMA缓存大小,32个数据(一个周期的正弦波点数)
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设寄存器地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;			 //内存地址寄存器递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设为16位(12位DAC)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//内存数据宽度采用16位模式,对应DAC12位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;			 //工作在循环缓存模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;		 //设置DMA通道优先级为高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;			 //不设置为内存到内存传输

	DMA_Init(DMA2_Channel4, &DMA_InitStructure);
	DMA_Cmd(DMA2_Channel4, ENABLE);		   

	/*使能DAC通道2:PA.5被自动连接到DAC的转换器*/
	DAC_Cmd(DAC_Channel_2, ENABLE);
	DAC_DMACmd(DAC_Channel_2, ENABLE);		 //使能DAC通道2的DMA
}

int main()
{
	SystemInit();
	DAC_Configuration();
	DMA_Configuration();
	for (int Idx = 0; Idx < 32; Idx++)
	{
		DAC2Sine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bit[Idx]);	//将正弦波离散点装入指定DAC2Sine12bit[]中(DMA指定的外设地址)
	}
	
	while(1)
	{			
		if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11)==0) KEY=1; // 按键1播放 
		else if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_12)==0) KEY=2; // 按键2停止 
				
		switch (KEY)
		{		
		    case 1:
		        for (i=0;i<68;i++)
			    {
		           if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_12)==0) 
				   {    
				       KEY=2;
					   TIM_Cmd(TIM3, DISABLE);
					   break;
					}		
		           TIM_Configuration(Redfrebit[i]);	   	//TIM2赋值改变频率,发不同音调
		           Delay_ms(300);
			    }
			    break;				
		    case 2:
	             TIM_Cmd(TIM3, DISABLE);	//不使能定时器(不让DAC输出)
		        Delay_ms(300);
			   break;
		}		
    }
}

互连通信接口设计

例1:USART初始化程序
#define U1Baud   115200
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

PUTCHAR_PROTOTYPE
{
	USART_SendData(USART1, (uint8_t) ch);   
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
	return ch;
}  // 定义之后,可以使用printf 

int flag = 0;

void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);			  //中断分组2
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; 		  //USART1接收中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;		  //次占优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;	
	NVIC_Init(&NVIC_InitStructure);

	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; 		  //USART2接收中断
	NVIC_Init(&NVIC_InitStructure);

}

void USART_Configuration(uint32_t UART1_Baud)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;

	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD 
						   |RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO, ENABLE);

  /*USART1端口配置PA9 TX 复用推挽输出 PA10 RX 浮空输入模式*/
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 ;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure); 

	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10 ;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
      	
    /*--------------USART1 配置-------------------*/
	USART_InitStructure.USART_BaudRate = UART1_Baud;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1, ENABLE);

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);		
}

void USART1_SendString(uint8_t *ch)
{
	while(*ch!=0)
	{		
		USART_SendData(USART1, *ch);
		while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
		ch++;
	}   	
}

void USART1_IRQHandler(void)
{
	char res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
        USART_ClearFlag(USART1, USART_IT_RXNE);		
	    res =USART_ReceiveData(USART1);		       // 读取接收到的数据USART1->DR
	    USART1_SendString("\r\n 接收到的字符是");
		while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
		USART_SendData(USART1, res);
		flag = 1;
	}  	
}

int main()
{
	SystemInit();
	NVIC_Configuration();
	USART_Configuration(U1Baud);
	//...... 
}

嵌入式应用系统设计实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NUAA_Peter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值