这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【i646593001】QuadCopter DIY进程帖

共76条 2/8 1 2 3 4 5 6 ›| 跳转至
高工
2014-05-20 10:30:49     打赏
11楼

很详细!期待楼主接下来的进程!!!

 


助工
2014-05-21 01:21:13     打赏
12楼

下载与调试:


1、借来同事的Jlink,连上电脑,安装Jlink的驱动程序,

2、认识SWD接口:


SWD 和传统的调试方式区别

    SWD 模式比 JTAG 在高速模式下面更加可靠。 在大数据量的情况下面 JTAG 下载程序会失败, 但是 SWD 发生的几率会小很多。基本使用 JTAG 仿真模式的情况下是可以直接使用 SWD 模式的, 只要你的仿真器支持。 所以推荐大家使用这个模式。

    在大家 GPIO 刚好缺一个的时候, 可以使用 SWD 仿真, 这种模式支持更少的引脚。

    在大家板子的体积有限的时候推荐使用 SWD 模式, 它需要的引脚少, 当然需要的 PCB 空间就小啦! 比如你可以选择一个很小的 2.54 间距的 5 芯端子做仿真接口


 


J-Link指定的标准接口


市面上的常用仿真器对 SWD 模式支持情况

(1) JLINKV6 支持 SWD 仿真模式, 速度较慢。

(2) JLINKV7 比较好的支持 SWD 仿真模式, 速度有了明显的提高,速度是 JLINKV6 的 6 倍。 
(3) JLINKV8 非常好的支持 SWD 仿真模式, 速度可以到 10M。
(4) ULINK1 不支持 SWD 模式。
(5) 盗版 ULINK2 非常好的支持 SWD 模式, 速度可以达到 10M。
(6) 正版 ULINK2 非常好的支持 SWD 模式, 速度可以达到 10M。

 

SWD 硬件接口上的不同

 

(1) JLINKV6 需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(2) JLINKV7 需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(3) JLINKV8 需要的硬件接口为: VCC, GND, RST, SWDIO, SWDCLK
(4) ULINK1 不支持 SWD 模式
(5) 盗版 ULINK2 需要的硬件接口为: GND, RST, SWDIO, SWDCLK
(6) 正版 ULINK2 需要的硬件接口为: GND, RST, SWDIO, SWDCLK



3、使用Jlink下载固件:

打开J-Flash ARM程序,打开将要下载的固件,并修改 Option 下 Project settings 项。

选择USB设备,目标接口选SWD,设置CPU型号等。

设置完成后,工程参数显示在左侧栏内,如下图:


板子加电后,依次选择 Target 菜单下 Unsecure Chip,Erase Chip,Program & Verify,Secure Chip即可。


4、Keil MDK打开一个工程,选项中Debug页设置如下:




助工
2014-05-21 23:09:46     打赏
13楼

LED指示灯实验


该实验考察GPIO的使用, STM32中GPIO有8种工作模式,资料见   http://blog.csdn.net/it1988888/article/details/7944314


从飞行器原理图.pdf文件中可以看到,飞行器臂上12个LED灯共同由PC13 接口控制。


int main(void)
{
       
  /* GPIOD Periph clock enable */
  int i = 0;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

  /* Configure PC13 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);


  while (1)
  {
    GPIO_SetBits(GPIOC,GPIO_Pin_13);
    for(i=0;i<10000000;i++);
    GPIO_ResetBits(GPIOC,GPIO_Pin_13);
    for(i=0;i<10000000;i++);
  }
}

 刚开始 i 值设置的太小,看不出结果,调试中能看到效果,后来改大就OK了


助工
2014-05-21 23:52:02     打赏
14楼

擦,发现自己的电脑没有串口,明儿找个USB转串口线了,看看资料先!


UART,是通用异步收发传输器(Universal Asynchronous Receiver / Transmitter),既然是“器”,显然,它就是个设备而已,要完成一个特定的功能的硬件,它本身并不是协议。那么它要完成什么功能呢?它的最基本功能,是串行数据和并行数据之间的转换。我们知道,计算机中的数据以Byte为基本单位,对一个Byte的存取是并行的,即,同时取得/写入8个bit。而串行通信,需要把这个Byte“打碎”,按照时间顺序来收发以实现串行。

    UART作为一种软件协议来看,是异步串口通信协议的英文缩写,它包括了RS232RS499RS423RS422RS485等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。RS232RS499RS423RS422RS485等,是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。实际上是属于通信网络中的物理层(最底层)的概念,与通信协议没有直接关系。而通信协议,是属于通信网络中的数据链路层(上一层)的概念。


程序修改的crazyflie的uart.c的程序,改一下端口定义即可,留证据:







助工
2014-05-23 01:19:10     打赏
15楼

今天阅读Crazyflie的程序,发现他们的代码中移植了freeRTOS,遂想在自己的四轴中使用同样的方法。参考网上相关的成功案例( http://www.amobbs.com/thread-5255622-1-1.html , http://www.****.com/auzxj/blog/11-11/235480_4fb3b.html ),移植成功了,总结一下。


一、下载FreeRTOS的源码

FreeRTOS项目地址: http://www.freertos.org/ ,好像被墙了,自己想办法。网站左上角有个带绿色图标的download 连接,然后。。。


二、解压FreeRTOS文件

我下载了一个FreeRTOSv8.0.1.exe 的文件,自解压文件,解压之。


打开在Source/portable目錄,保留RVDS和MemMang目錄,其餘可刪除。此文件夹根据不同的编译器进行配置,我的编译器是Keil,Keil中的文件与RVDS相同,因此保留RVDS。MemMang目录配置内存管理的文件。


三、FreeRTOS文件配置


1、复制下Source文件夹到工程下Lib文件夹,并重命名为FreeRTOS。


2、复制\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.h文件到工程文件夹,我是放在main.c文件的同一个目录.\User\下。


3、复制 Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_md.s
至.\user\並改檔名為STM32F10x.s,因为我是用STM32F103C8,若是其他容量请自行選對應的startup files。
在 __heap_limit 段后添加

                IMPORT xPortPendSVHandler
                IMPORT xPortSysTickHandler
                IMPORT vPortSVCHandler

__Vectors区段中断向量表将SVCall Handler、PendSV_Handler、SysTick Handler改由RTOS管理,这样stm32f10x_it.c就不会影响到这三个OD要用到的中断程序。直接注释掉旧的,添加新的

                ;DCD     SVC_Handler                ; SVCall Handler
                DCD     vPortSVCHandler           ; SVCall Handler

                ;DCD     PendSV_Handler             ; PendSV Handler  
                ;DCD     SysTick_Handler            ; SysTick Handler
                DCD     xPortPendSVHandler        ; PendSV Handler
                DCD     xPortSysTickHandler       ; SysTick Handler 


4、修改Project Items,如下图


list.c,queue.c,task.c文件位于原Source目录,port.c文件位于\Source\portable\RVDS\ARM_CM3\目录,heap_2.c文件位于\Source\portable\MemMang目录。同时记得更新StartUp Group下的.s文件为刚才修改过后的.s文件。


五、配置头文件路径

添加刚才加入的FreeRTOS相关路径,



六、编译文件

根据报错信息相应修改,直到编译通过。



七、LED程序移植

在freeRTOS系统下重新加入 led 指示灯的实验程序,编译,下载,查看效果。


代码不多,贴上:

/**
  ******************************************************************************
  * @file    GPIO/IOToggle/main.c 
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body.
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  *

	© COPYRIGHT 2011 STMicroelectronics

******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "misc.h"

#define LED0_ON()   GPIO_ResetBits(GPIOC,GPIO_Pin_13);
#define LED0_OFF()  GPIO_SetBits(GPIOC,GPIO_Pin_13);

static void prvSetupHardware( void );

/* Two demo Tasks*/       
static void vLEDTask( void *pvParameters );

void Led_Init(void);


int main(void)
{
       
  /* GPIOD Periph clock enable */
	prvSetupHardware();
	
	xTaskCreate(vLEDTask,(signed portCHAR *)"LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL );
	
	vTaskStartScheduler();

  return 0;	
}

void vLEDTask( void *pvParameters )
{
    for( ;; )
    {
    LED0_ON();
    vTaskDelay(1000/portTICK_RATE_MS);
    LED0_OFF();   
    vTaskDelay(1000/portTICK_RATE_MS);
    }
}

static void prvSetupHardware( void )
{
    SystemInit(); 
    Led_Init();
}
/*-----------------------------------------------------------*/

void Led_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );

    /*LED0 @ PA8*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init( GPIOC, &GPIO_InitStructure );    

}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/


 效果不错,以后工作就在freeRTOS下做吧。




助工
2014-06-06 13:59:49     打赏
16楼

好久没来,最近看了下Crazyflie的工程文件和圆点博士的工程文件,发现圆点博士的工程文件是对crazyflie工程的Keil MDK 工程化,仅修改了一些端口定义。也调试过代码,但用的是克隆版的Jlink,老是被查出来,而导致Keil闪退,下载不到板子上,所以干脆在网上重新买了一些工具,有ST-Link 和USB转TTL的模块,上图:

最右侧的为ST-link,作用和J-LINK一样的,不到三十块钱,左边两个为USB转TTL的模块,都是几块钱就能买到,终于可以继续折腾了。

欲善其事,先利其器,还是没错的。


助工
2014-06-07 00:09:54     打赏
17楼

PWM电机驱动实验


STM32参考手册中查到下表(http://blog.csdn.net/dazhaozi/article/details/6868414也有定义)


因为我们的四轴上四个马达接到了PA0~PA3上,所以需要用TIM2的4个channel,不用重映射。


配置PWM:

PWM的输出模式:详细定义见http://blog.sina.com.cn/s/blog_4a3946360100wh5w.html我们选择PWM1。

贴电机测试的源码:

 * motors.c - Motor driver
 *
 * This code mainly interfacing the PWM peripheral lib of ST.
 */

#include <stdbool.h>

#include "motors.h"

// ST lib includes
#include "stm32f10x_conf.h"

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

// HW defines
#define MOTORS_GPIO_TIM_PERIF     RCC_APB1Periph_TIM2
#define MOTORS_GPIO_TIM      TIM2
#define MOTORS_GPIO_TIM_DBG  DBGMCU_TIM2_STOP

#define MOTORS_GPIO_PERIF         RCC_APB2Periph_GPIOA
#define MOTORS_GPIO_PORT          GPIOA
#define MOTORS_GPIO_M1            GPIO_Pin_0 // TIM2_CH1
#define MOTORS_GPIO_M2            GPIO_Pin_1 // TIM2_CH2
#define MOTORS_GPIO_M3            GPIO_Pin_2 // TIM2_CH3
#define MOTORS_GPIO_M4            GPIO_Pin_3 // TIM2_CH4

/* Utils Conversion macro */
#define C_BITS_TO_16(X) ((X)<<(16-MOTORS_PWM_BITS))
#define C_16_TO_BITS(X) ((X)>>(16-MOTORS_PWM_BITS)&((1<<MOTORS_PWM_BITS)-1))

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

/* Public functions */

//Initialization. Will set all motors ratio to 0%
void motorsInit()
{
  //Init structures
  GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  TIM_OCInitTypeDef  TIM_OCInitStructure;

  if (isInit)
    return;

  //Enable gpio and the timer
  RCC_APB2PeriphClockCmd(MOTORS_GPIO_PERIF, ENABLE);
  RCC_APB1PeriphClockCmd(MOTORS_GPIO_TIM_PERIF, ENABLE);
	
  // Configure the GPIO for the timer output
  GPIO_InitStructure.GPIO_Pin = (MOTORS_GPIO_M1 |
                                 MOTORS_GPIO_M2 |
                                 MOTORS_GPIO_M3 |
                                 MOTORS_GPIO_M4);
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(MOTORS_GPIO_PORT, &GPIO_InitStructure);


  //Timer configuration
  TIM_TimeBaseStructure.TIM_Period = MOTORS_PWM_PERIOD;
  TIM_TimeBaseStructure.TIM_Prescaler = MOTORS_PWM_PRESCALE;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(MOTORS_GPIO_TIM, &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;

  TIM_OC1Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC1PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);

  TIM_OC2Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC2PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);

  TIM_OC3Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC3PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);

  TIM_OC4Init(MOTORS_GPIO_TIM, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(MOTORS_GPIO_TIM, TIM_OCPreload_Enable);

  //Enable the timer
  TIM_Cmd(MOTORS_GPIO_TIM, ENABLE);
  //Enable the timer PWM outputs
  TIM_CtrlPWMOutputs(MOTORS_GPIO_TIM, ENABLE);
  // Halt timer during debug halt.
  DBGMCU_Config(MOTORS_GPIO_TIM_DBG, ENABLE);
  
  isInit = true;
}

bool motorsTest(void)
{
  int i;

  for (i = 0; i < sizeof(MOTORS) / sizeof(*MOTORS); i++)
  {
    motorsSetRatio(MOTORS[i], MOTORS_TEST_RATIO);
    vTaskDelay(M2T(MOTORS_TEST_ON_TIME_MS));
    motorsSetRatio(MOTORS[i], 0);
    vTaskDelay(M2T(MOTORS_TEST_DELAY_TIME_MS));
  }
  return isInit;
}


void motorsSetRatio(int id, uint16_t ratio)
{
  switch(id)
  {
    case MOTOR_M1:
      TIM_SetCompare1(MOTORS_GPIO_TIM, C_16_TO_BITS(ratio));
      break;
    case MOTOR_M2:
      TIM_SetCompare2(MOTORS_GPIO_TIM, C_16_TO_BITS(ratio));
      break;
    case MOTOR_M3:
      TIM_SetCompare3(MOTORS_GPIO_TIM, C_16_TO_BITS(ratio));
      break;
    case MOTOR_M4:
      TIM_SetCompare4(MOTORS_GPIO_TIM, C_16_TO_BITS(ratio));
      break;
  }
}

int motorsGetRatio(int id)
{
  switch(id)
  {
    case MOTOR_M1:
      return C_BITS_TO_16(TIM_GetCapture1(MOTORS_GPIO_TIM));
    case MOTOR_M2:
      return C_BITS_TO_16(TIM_GetCapture2(MOTORS_GPIO_TIM));
    case MOTOR_M3:
      return C_BITS_TO_16(TIM_GetCapture3(MOTORS_GPIO_TIM));
    case MOTOR_M4:
      return C_BITS_TO_16(TIM_GetCapture4(MOTORS_GPIO_TIM));
  }

  return -1;
}

// FreeRTOS Task to test the Motors driver
void motorsTestTask(void* params)
{
  static const int sequence[] = {0.1*(1<<16), 0.15*(1<<16), 0.2*(1<<16), 0.25*(1<<16)};
  int step=0;

  //Wait 3 seconds before starting the motors
  vTaskDelay(M2T(3000));

  while(1)
  {
    motorsSetRatio(MOTOR_M4, sequence[step%4]);
    motorsSetRatio(MOTOR_M3, sequence[(step+1)%4]);
    motorsSetRatio(MOTOR_M2, sequence[(step+2)%4]);
    motorsSetRatio(MOTOR_M1, sequence[(step+3)%4]);

    if(++step>3) step=0;

    vTaskDelay(M2T(1000));
  }
}

 


下面是main.c文件的内容:

/* Includes */
#include "stm32f10x.h"

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "misc.h"

#include "led.h"
#include "motors.h"
#include "uart.h"

/* Private functions */
static void prvClockInit(void);
static void prvSetupHardware( void );



int main(void)
{
  prvClockInit();
  /* GPIOD Periph clock enable */
	prvSetupHardware();
	
	xTaskCreate(vLEDTask,(portCHAR *)"LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL );
	xTaskCreate(vUartSendTask,(portCHAR *)"UartSend", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL);
	xTaskCreate(motorsTestTask,(portCHAR *)"MotorTest",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY+2,NULL);
	xTaskCreate(adcTask,(portCHAR *)"LED",configMINIMAL_STACK_SIZE,NULL,tskIDLE_PRIORITY+3,NULL);
	
	vTaskStartScheduler();

  return 0;	
}

static void prvSetupHardware( void )
{
    SystemInit(); 
    ledInit();
    motorsInit();
    uartInit();
}
/*-----------------------------------------------------------*/

//Clock configuration
static void prvClockInit(void)
{
  ErrorStatus HSEStartUpStatus;

  RCC_DeInit();
  // Enable HSE 
  RCC_HSEConfig(RCC_HSE_ON);
  // Wait till HSE is ready 
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if (HSEStartUpStatus == SUCCESS)
  {
    // HCLK = SYSCLK 
    RCC_HCLKConfig(RCC_SYSCLK_Div1);

    // PCLK2 = HCLK 
    RCC_PCLK2Config(RCC_HCLK_Div1);

    // PCLK1 = HCLK/2 
    RCC_PCLK1Config(RCC_HCLK_Div2);

    // Flash 2 wait state 
    FLASH_SetLatency(FLASH_Latency_2);

    // Enable Prefetch Buffer 
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    // ADCCLK = PCLK2/6 = 72 / 6 = 12 MHz
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    // PLLCLK = 16MHz/2 * 9 = 72 MHz 
    RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);

    // Enable PLL 
    RCC_PLLCmd(ENABLE);

    // Wait till PLL is ready 
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    // Select PLL as system clock source 
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    // Wait till PLL is used as system clock source 
    while(RCC_GetSYSCLKSource() != 0x08);
  } else {
      GPIO_InitTypeDef GPIO_InitStructure;
  
    //Cannot start the main oscillator: LED of death...
    GPIO_InitStructure.GPIO_Pin = LED2_GPIO;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

    GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = LED3_GPIO;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;

    GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStructure);

    GPIO_ResetBits(LED2_GPIO_PORT, LED2);
    GPIO_ResetBits(LED3_GPIO_PORT, LED3);

    //Cannot start xtal oscillator!
    while(1); 
  }
}




运行后电机动起来了



助工
2014-06-07 01:50:45     打赏
18楼

ADC电池电压监测

我们用的板子VBAT接PB1端口,查表:


选择ADC1,通道9。


ADC的工作模式等定义,见http://blog.csdn.net/fouder_li/article/details/6718884


ADC终于打印数据了,前者是后者的2倍左右,是因为vbat经过2分压后传递给PB1接口的。


程序沿用crazyflie的程序,修改端口的定义和外部触发的定时器。

1、GPIO_VBAT 修改为GPB1。

2、参照上表,GPB1 对于的ADC Channel为 ADC_Channel_9。

3、修改ADC_ExternalTrigConv为T4CC4。

crazyflie使用了TIM2的Channel2,因为我们的电机接了TIM2,所以在这里改成了T4C4。

4、修改定时器及通道为TIM4,Channel4。

5、修改adc.h文件里的ADC_INTERNAL_VREF,此处原值为1.20,应该改为3.30。

暂时就这么多吧,下面是adc.c的代码,有错误请指出。


#include "stm32f10x_conf.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "adc.h"
#include "pm.h"
#include "nvicconf.h"
#include "imu.h"

#include "uart.h"
//#include "acc.h"

// PORT A
#define GPIO_VBAT        GPIO_Pin_1

// CHANNELS
#define NBR_OF_ADC_CHANNELS   1
#define CH_VBAT               ADC_Channel_9

#define CH_VREF               ADC_Channel_17
#define CH_TEMP               ADC_Channel_16

static bool isInit;
volatile AdcGroup adcValues[ADC_MEAN_SIZE * 2];

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 = NBR_OF_ADC_CHANNELS * (ADC_MEAN_SIZE * 2);
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
  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
  DMA_Cmd(DMA1_Channel1, ENABLE);
}

/**
 * Decimates the adc samples after oversampling
 */
static void adcDecimate(AdcGroup* oversampled, AdcGroup* decimated)
{
  uint32_t i, j;
  uint32_t sum;
  uint32_t sumVref;
  AdcGroup* adcIterator;
  AdcPair *adcOversampledPair;
  AdcPair *adcDecimatedPair;

  // Compute sums and decimate each channel
  adcDecimatedPair = (AdcPair*)decimated;
  for (i = 0; i < NBR_OF_ADC_CHANNELS; i++)
  {
    adcIterator = oversampled;
    sum = 0;
    sumVref = 0;
    for (j = 0; j < ADC_MEAN_SIZE; j++)
    {
      adcOversampledPair = &((AdcPair*)adcIterator)[i];
      sum += adcOversampledPair->val;
      sumVref += adcOversampledPair->vref;
      adcIterator++;
    }
    // Decimate
    adcDecimatedPair->val = sum / ADC_DECIMATE_DIVEDEND;
    adcDecimatedPair->vref = sumVref / ADC_DECIMATE_DIVEDEND;
    adcDecimatedPair++;
  }
}

void adcInit(void)
{

	GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef ADC_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

  if(isInit)
    return;

  // Enable TIM4, GPIOA and ADC1 clock
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 |
                         RCC_APB2Periph_GPIOA, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOB, &GPIO_InitStructure);				

  //Timer configuration
  TIM_TimeBaseStructure.TIM_Period = ADC_TRIG_PERIOD;
  TIM_TimeBaseStructure.TIM_Prescaler = ADC_TRIG_PRESCALE;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

  // TIM4 channel4 configuration in PWM mode
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 1;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC4Init(TIM4, &TIM_OCInitStructure);
  TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
  // Halt timer 2 during debug halt.
  DBGMCU_Config(DBGMCU_TIM4_STOP, ENABLE);

  adcDmaInit();

  // ADC1 configuration
  ADC_DeInit(ADC1);
  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T4_CC4;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = NBR_OF_ADC_CHANNELS;
  ADC_Init(ADC1, &ADC_InitStructure);

  // ADC1 channel sequence
  ADC_RegularChannelConfig(ADC1, CH_VREF, 1, ADC_SampleTime_28Cycles5);

  // ADC2 configuration
  ADC_DeInit(ADC2);
  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = NBR_OF_ADC_CHANNELS;
  ADC_Init(ADC2, &ADC_InitStructure);

  // ADC2 channel sequence
  ADC_RegularChannelConfig(ADC2, CH_VBAT, 1, ADC_SampleTime_28Cycles5);

  // Enable ADC1
  ADC_Cmd(ADC1, ENABLE);
  // Calibrate ADC1
  ADC_ResetCalibration(ADC1);
  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1));

  // Enable ADC1 external trigger
  ADC_ExternalTrigConvCmd(ADC1, ENABLE);
  ADC_TempSensorVrefintCmd(ENABLE);

  // Enable ADC2
  ADC_Cmd(ADC2, ENABLE);
  // Calibrate ADC2
  ADC_ResetCalibration(ADC2);
  while(ADC_GetResetCalibrationStatus(ADC2));
  ADC_StartCalibration(ADC2);
  while(ADC_GetCalibrationStatus(ADC2));

  // Enable ADC2 external trigger
  ADC_ExternalTrigConvCmd(ADC2, ENABLE);

  // 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*));
  xTaskCreate(adcTask, (const signed char *)"ADC", configMINIMAL_STACK_SIZE, NULL, /*priority*/3, NULL);

	printf("this is in adcInit\r\n");

  isInit = true;
}

bool adcTest(void)
{
  return isInit;
}

float adcConvertToVoltageFloat(uint16_t v, uint16_t vref)
{
  return ((v<<1) / (vref / ADC_INTERNAL_VREF));
}

void adcDmaStart(void)
{
  // Enable the Transfer Complete and Half Transfer Interrupt
  DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE);
  // Enable ADC1 DMA
  ADC_DMACmd(ADC1, ENABLE);
  // TIM4 counter enable
  TIM_Cmd(TIM4, ENABLE);
}

void adcDmaStop(void)
{
//  TIM_Cmd(TIM4, DISABLE);
}

void adcInterruptHandler(void)
{
  portBASE_TYPE xHigherPriorityTaskWoken;
  AdcGroup* adcBuffer;

  if(DMA_GetITStatus(DMA1_IT_HT1))
  {
    DMA_ClearITPendingBit(DMA1_IT_HT1);
    adcBuffer = (AdcGroup*)&adcValues[0];
    xQueueSendFromISR(adcQueue, &adcBuffer, &xHigherPriorityTaskWoken);
  }
  if(DMA_GetITStatus(DMA1_IT_TC1))
  {
    DMA_ClearITPendingBit(DMA1_IT_TC1);
    adcBuffer = (AdcGroup*)&adcValues[ADC_MEAN_SIZE];
    xQueueSendFromISR(adcQueue, &adcBuffer, &xHigherPriorityTaskWoken);
  }
}

void adcTask(void *param)
{
  AdcGroup* adcRawValues;
  AdcGroup adcValues;

  vTaskSetApplicationTaskTag(0, (pdTASK_HOOK_CODE)TASK_ADC_ID_NBR);
  vTaskDelay(1000);

  adcDmaStart();

  while(1)
  {
    xQueueReceive(adcQueue, &adcRawValues, portMAX_DELAY);
    adcDecimate(adcRawValues, &adcValues);  // 10% CPU
//    pmBatteryUpdate(&adcValues);

    vTaskDelay(250);
    printf(" vbat.val: %04x, vbat.vref: %04x\r\n",adcValues.vbat.val,adcValues.vbat.vref);
//    uartSendData(sizeof(AdcGroup)*ADC_MEAN_SIZE, (uint8_t*)adcRawValues);

  }
}





助工
2014-06-07 01:51:54     打赏
19楼

NRF无线通讯实验


此处要自己写通讯协议?用于遥控器和飞行器交互通讯。

通讯协议已经分析了,我是传送门

前段时间歇了一段时间,完了一段时间的树莓派,现在重拾旧业,弄了几天的nrf24l01+,终于实现了通信,虽花了大把的时间,但也是很有收获。

工程是在crazyflie的工程基础上修改得到的。运行了freeRTOS实时操作系统,在接收到中断后通过发送信号量等过程最后收到数据,因此程序比较复杂。在调试中对函数中断,中断服务程序编写,中断线程,及nrf24l01的设置等都慢慢克服,终于实现了遥控器发送,四轴接收的功能。

录视频太麻烦,来张图片简单见证:




助工
2014-06-07 01:59:10     打赏
20楼

MPU6050传感器驱动实验

用crazyflie的I2C程序,要改的地方比较多,找到其他资料:

http://blog.csdn.net/elong_2009/article/details/8189700

先保存,看看再说。


在crazyflie的I2C程序中,关于DMA的Channel,相关资料见:

http://blog.csdn.net/zzwdkxx/article/details/9026173



STM32单片机的IIC硬件编程---查询等待方式

http://blog.csdn.net/WangSanHuai2010/article/details/5652071


关于MPU6050的详细资料,可以找相关文档,下面的网址上的说明也比较详细,需要了解的可以去看看:

http://blog.sina.com.cn/s/blog_8240cbef01018i10.html


今天调通了MPU6050,工程文件及结果见http://forum.eepw.com.cn/thread/251222/3#27






共76条 2/8 1 2 3 4 5 6 ›| 跳转至

回复

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