OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【i646593001】两轮子平衡小车DIY 进程帖

共17条 1/2 1 2 跳转至

【i646593001】两轮子平衡小车DIY 进程帖

助工
2015-06-07 16:44:24    评分



关键词: 平衡     小车     进程    

助工
2015-06-08 00:07:21    评分
2楼

组装过程

没什么好多说的,比较简单,细心一点就好了。


电池及电机位置摆放:


视频地址:http://player.youku.com/player.php/sid/XMTI1NzM0MTQ0MA==/v.swf


助工
2015-06-08 00:31:01    评分
3楼

FreeRTOS移植

 

开发环境: keil uVersion5 ST-linkUSBTTL

去年玩四轴的时候用过FreeRTOS,觉得还算好用,今年继续用这个吧。RTOS,实时操作系统,有兴趣的可以去谷歌。以后的开发实验都在这个系统上进行了。

 

一、新建文件夹Balancer123,作为我们存放工程的目录,在里面新建lib,list,output,user四个文件夹,并新建一个空工程:



二、下载FreeRTOS压缩文件包,下载STM32库函数文件stsw-stm32054.zip(STM32F10x_StdPeriph_Lib_V3.5.0),并分别解压出FreeRTOSV8.2.1、STM32F10x_StdPeriph_Lib_V3.5.0两个文件夹。

三、将解压出来的外设库中STM32F10x_StdPeriph_Lib_V3.5.0\Libraries下两个文件夹拷至工程Lib目录,复制FreeRTOSV8.2.1\FreeRTOS\Source文件夹到工程下Lib文件夹,并重命名为FreeRTOS。


1复制\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template目录下stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h文件至\user\目录下。

2复制FreeRTOSV8.2.1\FreeRTOS\Demo\CORTEX_STM32F103_Keil目录下FreeRTOSConfig.h和main.c文件到工程文件夹的\user\目录下。

 3复制Balancer123\lib\CMSIS\CM3\DeviceSupport\ST\STM32F10x目录下

stm32f10x.hsystem_stm32f10x.csystem_stm32f10x.h三个文件至\user\目录下。

 4复制Balancer123\lib\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm目录下startup_stm32f10x_md.s文件到\user\目录下并改名为STM32F10x.s(该文件为系统的启动文件,适用于64K-128K Flash空间的芯片)。取消该STM32F10x.s文件只读属性,修改如下:

在 __heap_limit(位于50行) 段后添加

 

                IMPORT xPortPendSVHandler

                IMPORT xPortSysTickHandler

                IMPORT vPortSVCHandler

 

__Vectors区段中断向量表将SVCall HandlerPendSV_HandlerSysTick Handler改由RTOS管理。直接注释掉旧的,添加新代码并保存。

 

                ;DCD     SVC_Handler                ; SVCall Handler

                DCD     vPortSVCHandler           ; SVCall Handler

 

                ;DCD     PendSV_Handler             ; PendSV Handler  

                DCD     xPortPendSVHandler        ; PendSV Handler

                ;DCD     SysTick_Handler            ; SysTick Handler

                DCD     xPortSysTickHandler       ; SysTick Handler 

四、如下图进入工程项目管理菜单。


笔者简单分了四组,分别是userlibfreertosdrivers。三组中分别添加文件,如下图:


1、User添加user目录下四个程序文件。
2、lib添加Balancer123\lib\STM32F10x_StdPeriph_Driver\src目录下所有c文件。
3、freertos添加\Balancer123\lib\FreeRTOS\目录下list.c,queue.c,task.c,timer.c四个文件及Balancer123\lib\FreeRTOS\portable\MemMang\目录下heap_2.c文件及Balancer123\lib\FreeRTOS\portable\RVDS\ARM_CM3\目录下port.c文件。最后一个目录下有个portmacro.h文件后面也会用得到。

4、Drivers文件夹留待以后存放自己编写的设备驱动,如电机,编码器,i2c设备,spi设备等。

添加完成后如下图所示:


五、配置属性:


选择时钟频率为72.0,选中右上角的“Use MicroLIB”复选框。


点击“Seletc Folder for Objects...”选择工程目录下创建的output文件夹,选中下面的“Create Hex File”复选框。


同上步一样选择listing目录为工程中的list文件夹。


定义“Preprocessor Symbols”,添加“USE_STDPERIPH_DRIVER,STM32F10X_MD”表示使用标准外设库并使用中等容量Flash的芯片。定义“IncludePaths”,添加需要用到的头文件的路径,如上所示就差不多了。记得添加Balancer123\lib\FreeRTOS\portable\RVDS\ARM_CM3目录到头文件目录,里面有portmacro.h文件需要用到。


笔者使用ST-link,设置右上角为“ST-Link Debugger”并点右侧“Settings”按钮配置,调出配置菜单。“Debug”页修改左侧菜单中的“ort:”改为“SW”,“Flash Download”页在“Download Functions”中选中“reset and Run”,这样程序下载到flash后自动运行。点击“Add”按钮添加Flash 编程方法,选128K的那项,即下载到芯片中的Flash中。如下图所示



六、编译程序
由于使用了其他工程的main.c文件,把用到的不必要的头文件,宏定义,其他功能或函数都删除。仅保留 static void prvSetupHardware( void )函数即可(该函数最后一行如果提示有错误可以删掉),该函数初始化对时钟等初始化。Main()函数删减到
int main( void )
{

prvSetupHardware();


/* Start the scheduler. */
vTaskStartScheduler();

/* Will only get here if there was not enough heap space to create the
idle task. */
return 0;
}
即可。编译一下,对可能出的错误按提示修改。如果没错误,一个空的工程建立成功了。


院士
2015-06-08 09:03:06    评分
4楼
不错~~

助工
2015-06-08 13:12:26    评分
5楼

LED GPIO端口测试

LED端口定义如下:

驱动很简单,往PB8端口输出0后LED亮,输出1时LED灭,直接贴程序代码:

#include "led.h"

#include "stm32f10x.h"

#include <stdbool.h>

/*FreeRtos includes*/
#include "FreeRTOS.h"
#include "task.h"

//Hardware configuration
#define LED_GPIO_PERIF   RCC_APB2Periph_GPIOB		
#define LED_GPIO_PORT    GPIOB						
#define LED_GPIO_GREEN   GPIO_Pin_8						
#define LED_POL_GREEN    LED_POL_NEG

static bool isInit=false;
void ledSet(bool value);


//Initialize the green led pin as output
void ledInit()
{

  GPIO_InitTypeDef GPIO_InitStructure;

  if(isInit)
    return;

  // Enable GPIO
  RCC_APB2PeriphClockCmd(LED_GPIO_PERIF, ENABLE);

  //Initialize the LED pins as an output
  GPIO_InitStructure.GPIO_Pin = LED_GPIO_GREEN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

  GPIO_Init(GPIOB, &GPIO_InitStructure);	

  //Turn off the LED:s
  ledSet(0);

  isInit = true;
}


bool ledTest(void)
{
  return isInit;
}


void ledSet(bool value)
{

  if(value)
    GPIO_ResetBits(GPIOB, LED_GPIO_GREEN); 
  else
    GPIO_SetBits(GPIOB, LED_GPIO_GREEN);

}

void vLEDTask( void *pvParameters )
{
    for( ;; )
    {
    ledSet(true);
    vTaskDelay(500);
    ledSet(false);
    vTaskDelay(2000);
    }
}

 

头文件很简单,就是对两个函数的声明。测试的时候只需在main函数中调用ledInit()函数并创建led任务即可以了。该任务功能是让led亮500ms,熄灭2000ms,循环执行。main函数如下:

int main( void )
{

	prvSetupHardware();

	ledInit();
	
	xTaskCreate(vLEDTask,"LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL );

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	
	return 0;
}

 



助工
2015-06-08 23:22:15    评分
6楼

电机驱动实验

   原理:通过STM32的定时器产生PWM信号,控制电机的转速。根据原理图知道,电机APB1,电机BPB0。根据下表定义知道,用到了定时器TIM3的CH4和CH3。

直接贴程序,通过程序基本上就弄懂原理了。可以直接使用初始化的程序。

#include <stdbool.h>
#include "stdio.h"
/* ST includes */
#include "stm32f10x.h"

#include "motors.h"

//FreeRTOS includes
#include "FreeRTOS.h"
#include "task.h"

// HW defines
#define MOTORS_GPIO_TIM_PERIF     RCC_APB1Periph_TIM3
#define MOTORS_GPIO_TIM_DBG       DBGMCU_TIM3_STOP
#define MOTORS_GPIO_TIM           TIM3

#define MOTORS_GPIO_PERIF         RCC_APB2Periph_GPIOB
#define MOTORS_GPIO_PORT          GPIOB
#define MOTORS_GPIO_M1            GPIO_Pin_1 // TIM3_CH4
#define MOTORS_GPIO_M2            GPIO_Pin_0 // TIM3_CH3

#define MOTORS_TIM_PERIF          RCC_APB1Periph_TIM3

#define M1_GPIO_IN1               GPIO_Pin_14
#define M1_GPIO_IN2               GPIO_Pin_15
#define M2_GPIO_IN1               GPIO_Pin_13
#define M2_GPIO_IN2               GPIO_Pin_12


const int MOTORS[] = { MOTOR_M1, MOTOR_M2};
static bool isInit = false;


void TIM3_GPIO_Config(void)
{
	
  GPIO_InitTypeDef GPIO_InitStructure;
	
  /* GPIOB clock enable */ 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);  
  /*GPIOB Configuration: TIM3 channel 3 and 4 as alternate function push-pull */ 
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 | GPIO_Pin_1; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_Init(GPIOB, &GPIO_InitStructure); 

  GPIO_InitStructure.GPIO_Pin =  M1_GPIO_IN1 | M1_GPIO_IN2 | M2_GPIO_IN1 | M2_GPIO_IN2; 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure); 
  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//stop jtag,enable swd

}

void TIM3_Mode_Config(void)
{
  //Init structures
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  //Timer configuration
  TIM_TimeBaseStructure.TIM_Period = MOTORS_PWM_PERIOD;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  //PWM channels configuration (All identical!)
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

  //M1:TIM3_CH3N
  TIM_OC3Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC3PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);
  //M2:TIM3_CH4N
  TIM_OC4Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);

//TIM_ARRPreloadConfig(TIM3,ENABLE);
  TIM_Cmd(TIM3,ENABLE);
  TIM_CtrlPWMOutputs(MOTORS_GPIO_TIM, ENABLE);
  DBGMCU_Config(MOTORS_GPIO_TIM_DBG, ENABLE);
	
}

void motor1SetDir(int ratio){
  if(ratio < 0){
    GPIO_ResetBits(GPIOB, M1_GPIO_IN1); 
    GPIO_SetBits(GPIOB, M1_GPIO_IN2);
    return;
  }
  GPIO_ResetBits(GPIOB, M1_GPIO_IN2); 
  GPIO_SetBits(GPIOB, M1_GPIO_IN1);
  return;
}

void motor2SetDir(int ratio){
  if(ratio < 0){
    GPIO_ResetBits(GPIOB, M1_GPIO_IN1); 
    GPIO_SetBits(GPIOB, M1_GPIO_IN2);
    return;
  }
  GPIO_ResetBits(GPIOB, M2_GPIO_IN2); 
  GPIO_SetBits(GPIOB, M2_GPIO_IN1);
  return;
}

/* Public functions */

//Initialization. Will set all motors ratio to 0%
void motorsInit(void)
{
  if (isInit)
    return;
	
  TIM3_GPIO_Config();
  TIM3_Mode_Config();

  isInit = true;
}

//-2047 <=  ration <= 2047
void motorsSetRatio(int id, int ratio)
{
  switch(id)
  {
    case MOTOR_M1:
      motor1SetDir(ratio);
      TIM_SetCompare4(TIM3, ratio);
      break;
    case MOTOR_M2:
      motor2SetDir(ratio);
      TIM_SetCompare3(TIM3, ratio);
      break;
  }
}

// FreeRTOS Task to test the Motors driver
void motorsTestTask(void* params)
{

  //Wait 3 seconds before starting the motors
  vTaskDelay(3000);
	
  motorsSetRatio(MOTOR_M1, 100);
  motorsSetRatio(MOTOR_M2, 100);

  while(1)
  {
    printf("This is in motorsTestTask\r\n");
    vTaskDelay(1000);
  }
}

 



助工
2015-06-08 23:40:37    评分
7楼

编码器数据采集实验

电机驱动器将两组编码器输出信号分别接到PA0PA1PB6PB7接口。如下图所示,用到TIM2 的CH1、CH2,TIM4的CH1、CH2。



直接贴代码,初始化的部分可以直接使用。不懂得找找百度谷歌,应该不太难。程序每半秒输出一次编码器的位置。头文件仅添加了两个public函数的声明。

#include <stdbool.h>
#include "stdio.h"
/* ST includes */
#include "stm32f10x.h"

#include "encoder.h"

//FreeRTOS includes
#include "FreeRTOS.h"
#include "task.h"


#define ENCODER1_GPIO_PERIF       RCC_APB2Periph_GPIOA
#define ENCODER1_GPIO_PORT        GPIOA
#define ENCODER1_GPIO_A           GPIO_Pin_0
#define ENCODER1_GPIO_B           GPIO_Pin_1

#define ENCODER2_GPIO_PERIF       RCC_APB2Periph_GPIOB
#define ENCODER2_GPIO_PORT        GPIOB
#define ENCODER2_GPIO_A           GPIO_Pin_6
#define ENCODER2_GPIO_B           GPIO_Pin_7

#define ENCODER1_TIMER            TIM2
#define ENCODER2_TIMER            TIM4

void EncoderInit(void)
{
  
  GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

  RCC_APB2PeriphClockCmd(ENCODER1_GPIO_PERIF | ENCODER2_GPIO_PERIF,ENABLE);  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM4, ENABLE);

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin = ENCODER1_GPIO_A | ENCODER1_GPIO_B;
  GPIO_Init(ENCODER1_GPIO_PORT,&GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = ENCODER2_GPIO_A | ENCODER2_GPIO_B;
  GPIO_Init(ENCODER2_GPIO_PORT,&GPIO_InitStructure);

  
  /* Timer configuration in Encoder mode */
  TIM_DeInit(ENCODER1_TIMER);
  TIM_DeInit(ENCODER2_TIMER);

  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseInit(ENCODER1_TIMER, &TIM_TimeBaseStructure);
  TIM_TimeBaseInit(ENCODER2_TIMER, &TIM_TimeBaseStructure);

  TIM_EncoderInterfaceConfig(ENCODER1_TIMER, TIM_EncoderMode_TI12, 
                             TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
  TIM_EncoderInterfaceConfig(ENCODER2_TIMER, TIM_EncoderMode_TI12, 
                             TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

  //Reset counter
  ENCODER1_TIMER->CNT = 0;
  ENCODER2_TIMER->CNT = 0;

  TIM_Cmd(ENCODER1_TIMER, ENABLE);
  TIM_Cmd(ENCODER2_TIMER, ENABLE);

}

void vEncoderTestTask(void* params){

  uint16_t counter1,counter2;
  
  while(1){
    counter1 = TIM_GetCounter(ENCODER1_TIMER);
    counter2 = TIM_GetCounter(ENCODER2_TIMER);
    printf("Encoder counter %7d %7d\r\n",counter1,counter2);
    vTaskDelay(500);
  }
  
}

 





助工
2015-06-09 00:42:16    评分
8楼

ADC实验

该实验测量电池电压,是不可省略的一部分。由于ADC中有一项是测量STM32芯片内温度的,顺便求出温度。采用ADC1的DMA方式读取。DMA1选择通道1,如下图所示:

至于ADC1的通道选择,查下表:


原理图中通过分压后接PA4,因此选择ADC1的通道4,通道16,通道17:


直接贴代码,照着代码比较容易理解。一次采集三个数据,采集完16组数据并通过DMA传给数组后,产生一个中断。中断处理函数对数组中的值求均值作为ADC的结果。代码应该没问题,相关函数可以直接copy & paste使用。


#include "stm32f10x.h"  
#include "FreeRTOS.h"  
#include "task.h"  
#include "semphr.h"  
#include "adc.h"  
  
#include "uart1.h"  
#include "Nvicconf.h"  
#include "stdio.h"  
  
#define NVIC_ADC_PRI          12  
  
// PORT A  
#define GPIO_VBAT        GPIO_Pin_4  
  
// CHANNELS  
#define CH_VBAT               ADC_Channel_4  
#define CH_VREF               ADC_Channel_17  
#define CH_TEMP               ADC_Channel_16  
#define ADC_DECIMATE_TO_BITS  12  
#define ADC_MEAN_SIZE         16  
  
#define ADC_RESOLUTION        12  
#define ADC_DECIMATE_DIVEDEND (ADC_MEAN_SIZE)  
  
#define ADC_SAMPLING_FREQ      100  
#define ADC_OVERSAMPLING_FREQ  (ADC_SAMPLING_FREQ * ADC_MEAN_SIZE)  
  
#define ADC_TRIG_PRESCALE       1  
#define ADC_TRIG_PRESCALE_FREQ  (72000000 / (ADC_TRIG_PRESCALE + 1))  
#define ADC_TRIG_PERIOD         (ADC_TRIG_PRESCALE_FREQ / (ADC_OVERSAMPLING_FREQ))  
  
#define ADC_INTERNAL_VREF   1.20  
  
/******** Types ********/  
  
  /*
typedef struct  
{  
  uint16_t vbat;  
  uint16_t vtemp;  
  uint16_t vref;  
} AdcGroup;  
  */
  
  
static bool isInit;  
volatile AdcGroup adcValues[ADC_MEAN_SIZE];  
  
xQueueHandle      adcQueue;  
  
static void adcDmaInit(void)  
{  
  DMA_InitTypeDef DMA_InitStructure;  
  
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  
  
  // DMA channel1 configuration  
  DMA_DeInit(DMA1_Channel1);  
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;  
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adcValues;  
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  
  DMA_InitStructure.DMA_BufferSize = 3*(ADC_MEAN_SIZE);  
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  
  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_VeryHigh;  
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);  
  // Enable DMA channel1  
  // Enable the Transfer Complete Interrupt  
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);  
  DMA_Cmd(DMA1_Channel1, ENABLE);  
}  
  
  
/** 
 * Decimates the adc samples after oversampling 
 */  
static void adcDecimate(AdcGroup* oversampled, AdcGroup* decimated)  
{  
  uint32_t i;  
  uint32_t sumVbat;  
  uint32_t sumVtemp;  
  uint32_t sumVref;  
  AdcGroup *adcIterator;  
  AdcGroup *adcOversampledGroup;  
  
  // Compute sums and decimate  
  
  adcIterator = oversampled;  
  sumVbat = 0;  
  sumVtemp = 0;  
  sumVref = 0;  
  for (i = 0; i < ADC_MEAN_SIZE; i++)  
  {  
    adcOversampledGroup = &((AdcGroup*)adcIterator)[i];  
    sumVbat += adcOversampledGroup->vbat;  
    sumVtemp += adcOversampledGroup->vtemp;  
    sumVref += adcOversampledGroup->vref;  
  }  
    // Decimate  
  decimated->vbat = sumVbat / ADC_DECIMATE_DIVEDEND;  
  decimated->vtemp = sumVtemp / ADC_DECIMATE_DIVEDEND;  
  decimated->vref = sumVref / ADC_DECIMATE_DIVEDEND;  
}  
  
void adcInit(void)  
{  
  
  GPIO_InitTypeDef GPIO_InitStructure;  
  ADC_InitTypeDef ADC_InitStructure;  
  NVIC_InitTypeDef NVIC_InitStructure;  
  
  if(isInit)  
    return;  
  
  // Enable TIM2, GPIOA and ADC1 clock  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);  
    
  RCC_ADCCLKConfig(RCC_PCLK2_Div6);  
  
  GPIO_InitStructure.GPIO_Pin = GPIO_VBAT;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;  
  GPIO_Init(GPIOB, &GPIO_InitStructure);          

  // ADC1 configuration  
  ADC_DeInit(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 = 3;  
  ADC_Init(ADC1, &ADC_InitStructure);  
  
  // ADC1 channel sequence  
  ADC_RegularChannelConfig(ADC1, CH_VBAT, 1, ADC_SampleTime_239Cycles5);  
  ADC_RegularChannelConfig(ADC1, CH_TEMP, 2, ADC_SampleTime_239Cycles5);  
  ADC_RegularChannelConfig(ADC1, CH_VREF, 3, ADC_SampleTime_239Cycles5);  
  
  // Enable ADC1 external trigger  
  ADC_ExternalTrigConvCmd(ADC1, DISABLE);  
  ADC_TempSensorVrefintCmd(ENABLE);  
  
  adcDmaInit();  
  
  // Enable ADC1 DMA  
  ADC_DMACmd(ADC1, ENABLE);  
  
  // Enable ADC1  
  ADC_Cmd(ADC1, ENABLE);  
  // Calibrate ADC1  
  ADC_ResetCalibration(ADC1);  
  while(ADC_GetResetCalibrationStatus(ADC1));  
  ADC_StartCalibration(ADC1);  
  while(ADC_GetCalibrationStatus(ADC1));  
  
  // Enable the DMA1 channel1 Interrupt  
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;  
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_ADC_PRI;  
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
  NVIC_Init(&NVIC_InitStructure);  
  
  adcQueue = xQueueCreate(1, sizeof(AdcGroup*));  
  
  
  printf("this is in adcInit\r\n");  
  isInit = true;  
}  
  
  
float adcConvertToVoltageFloat(uint16_t v, uint16_t vref)  
{  
  return (v / (vref / ADC_INTERNAL_VREF));  
}  
  
float adcConvertToTempFloat(uint16_t v, uint16_t vref)  
{  
  return 25.0 + (1.43 - (v / (vref / ADC_INTERNAL_VREF)))*232.56;  
}  
  
  
void adcInterruptHandler(void)  
{  
  portBASE_TYPE xHigherPriorityTaskWoken;  
  AdcGroup* adcBuffer;  
  
  if(DMA_GetITStatus(DMA1_IT_TC1))  
  {  
    DMA_ClearITPendingBit(DMA1_IT_TC1);  
    adcBuffer = (AdcGroup*)&adcValues[0];  
    xQueueSendFromISR(adcQueue, &adcBuffer, &xHigherPriorityTaskWoken);  
  }  
}  
  
  
void vAdcTask(void *param)  
{  
  AdcGroup* adcRawValues;  
  AdcGroup adcValues;  
  float vbat;  
  float temp;  
  
  vTaskDelay(1000);  
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  while(1)  
  {  
    xQueueReceive(adcQueue, &adcRawValues, portMAX_DELAY);  
    adcDecimate(adcRawValues, &adcValues);  // 10% CPU  
  
    vbat = adcConvertToVoltageFloat(adcValues.vbat,adcValues.vref);  
    temp = adcConvertToTempFloat(adcValues.vtemp,adcValues.vref);  
      
    printf("ADC %04x %04x %04x",adcValues.vbat,adcValues.vtemp,adcValues.vref);  
    printf("  %.2f   %.2f\r\n",vbat*7.73,temp);  
    vTaskDelay(5000);  
  }  
}  

 




助工
2015-06-10 13:55:29    评分
9楼

板载按键程序

板子上有个按键,连接到PB5,如图:

决定通过外部中断方式检测按键操作,如果按键被按下,PB5电平被拉低,产生一个下降沿。

因此,相关宏定义如下:

#define GPIO_PORT_KEY GPIOB

#define GPIO_KEY GPIO_Pin_5

#define KEY_GPIO_IRQ_SRC_PORT GPIO_PortSourceGPIOB

#define KEY_GPIO_IRQ_SRC GPIO_PinSource5

#define KEY_GPIO_IRQ_LINE EXTI_Line5

#define KEY_EXTI_IRQn EXTI9_5_IRQn

我们使用中断服务程序:EXTI9_5_IRQHandler。

程序比较简单,简单易懂。相关的初始化函数可以直接使用,keyTask函数每隔0.1秒输出一次值,该值由按键控制。

#include "key.h"
#include "stdio.h"

#include "FreeRTOS.h"
#include "task.h"
#include "uart1.h"

#define NVIC_KEY_PRI 14

#define GPIO_PORT_KEY GPIOB
#define GPIO_KEY  GPIO_Pin_5
#define KEY_GPIO_IRQ_SRC_PORT GPIO_PortSourceGPIOB
#define KEY_GPIO_IRQ_SRC  GPIO_PinSource5
#define KEY_GPIO_IRQ_LINE EXTI_Line5
#define KEY_EXTI_IRQn EXTI9_5_IRQn

static bool isInit;
uint8_t key;

void keyInit(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  key = 0x55;
  if(isInit)
    return;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

  /* Configure PULL UP -------------------------*/
  GPIO_InitStructure.GPIO_Pin = GPIO_KEY;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIO_PORT_KEY, &GPIO_InitStructure);

  GPIO_EXTILineConfig(KEY_GPIO_IRQ_SRC_PORT,KEY_GPIO_IRQ_SRC);
  EXTI_InitStructure.EXTI_Line = KEY_GPIO_IRQ_LINE;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  NVIC_InitStructure.NVIC_IRQChannel = KEY_EXTI_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = NVIC_KEY_PRI;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  isInit = true;
}

void keyInterruptHandler(void)
{
  if(EXTI_GetITStatus(KEY_GPIO_IRQ_LINE) != RESET)
  {
    key = ~key;
    EXTI_ClearITPendingBit(KEY_GPIO_IRQ_LINE);
  }
}

void keyTask(void *param)
{
  
  while(1)
  {
    vTaskDelay(100);
    printf("key1 : %x \r\n",key);
  }
}

 



菜鸟
2015-06-12 11:20:41    评分
10楼
很好很强大,一步步来,思路很清晰

共17条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]