论坛» DIY与开源设计» 电子DIY

【更新USB+ADC+PWM+UART,求各路大神检阅】liuwwei3 QuadCopter DIY进程贴

菜鸟
2014-03-31 13:14 1楼

今天收到东西开始工作-2014 3.31 1:00pm


经过几个小时的奋战,终于焊好了2014 3.31 10:21pm


焊好第一次试飞就成功了,哈哈,就是非得不太熟练




好久没更新啦,今天跟新一下进度,论坛格式太蛋疼了,学别人用表格

【手柄:USB+ADC】修改JOYStick实现简易鼠标 http://forum.eepw.com.cn/thread/249367/1#4
【手柄&飞机】串口调试 http://forum.eepw.com.cn/thread/249367/1#5
【飞机:PWM】螺旋桨转速控制 http://forum.eepw.com.cn/thread/249367/1#6














院士
2014-03-31 13:26 2楼
嗯,需要详细过程
菜鸟
2014-03-31 13:32 3楼
赞!
菜鸟
2014-05-04 22:44 4楼

更新内容:ADC+USB实现简易USB鼠标

首先USB是根据JOYStick改的。JOYStick源码目录:C:\Keil\ARM\Examples\ST\STM32F10xUSBLib\Demos。不同的安装目录可能有所不同。下面给出修改的内容:

首先修改"hw_config.c",在Set_System中删去一些没用的东西,删除后如下

void Set_System(void) { GPIO_InitTypeDef GPIO_InitStructure; /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration -----------------------------*/ /* RCC system reset(for debug purpose) */ RCC_DeInit(); /* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON); /* Wait till HSE is ready */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if (HSEStartUpStatus == SUCCESS) { /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* Flash 2 wait state */ FLASH_SetLatency(FLASH_Latency_2); /* HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* PCLK2 = HCLK */ RCC_PCLK2Config(RCC_HCLK_Div1); /* PCLK1 = HCLK/2 */ RCC_PCLK1Config(RCC_HCLK_Div2); /* On STICE the PLL output clock is fixed to 72 MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, 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) {} } /* enable the PWR clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE); /* USB_DISCONNECT used as USB pull-up */ GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); /* Connect EXTI Line9 */ GPIO_EXTILineConfig(GPIO_KEY_PORTSOURCE, GPIO_KEY_PINSOURCE); /* Configure EXTI Line9 to generate an interrupt on falling edge */ EXTI_InitStructure.EXTI_Line = GPIO_KEY_EXTI_Line; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); EXTI_ClearITPendingBit(EXTI_Line18); EXTI_InitStructure.EXTI_Line = EXTI_Line18; // USB resume from suspend mode EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); EXTI_ClearITPendingBit(GPIO_KEY_EXTI_Line); }

可能删的不够干净,不过不会影响我的程序,就不管了,下一步配置ADC,为了省事,我配置了八路ADC
手柄上共七个ADC,分别为ADC0~7,除ADC4之外,ADC0~7对应PA0~7
0,中间微调
1,右边微调
2,左边微调
3,没用,用于控制喇叭
4,左边上下
5,左边左右
6,右边左右
7,右边上下
ADC配置如下,我也不是很懂配置过程,找网上的教程搞定的,上代码:
void ADC_Configuration() { //UART and DMA clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO |RCC_APB2Periph_ADC1 , ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输 //ADC pins config GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2 | GPIO_Pin_3| GPIO_Pin_4 | GPIO_Pin_5|GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //ADC config ADC_DeInit(ADC1); ADC_InitSturature.ADC_Mode = ADC_Mode_Independent; ADC_InitSturature.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式 ADC_InitSturature.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式 ADC_InitSturature.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发转换关闭 ADC_InitSturature.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitSturature.ADC_NbrOfChannel = M; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitSturature); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5 ); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置 状态则等待 ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态 while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则 等待 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //DMA config DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //DMA内存基地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地 DMA_InitStructure.DMA_BufferSize = N*M; //DMA通道的DMA缓存的大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器 不变 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度 为16位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道 DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道 }


代码有点长,里面包括ADC和DMA配置,要事先定义几个全局变量


#define N 50
#define M 8
vu16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址
vu16 After_filter[M]; //用来存放求平均值之后的结果
这里是采用每个值采样50次然后求平均值作为该次采样的值,求平均的函数如下
void filter() { vu32 sum = 0; u8 count; u8 index ; for(index=0;index

下面给出mian

int main(void) { #ifdef DEBUG debug(); #endif bool bflag = TRUE; u16 value[M]; u8 i; Set_System(); USB_Interrupts_Config(); Set_USBClock(); USB_Init(); USART_Configuration(); ADC_Configuration(); //printf("UART SUCCESS!!!"); while (1) { Delay(0xEFFFFF); filter(); if ((JoyState() != 0) & (bDeviceState == CONFIGURED)) { Joystick_Send(JoyState()); } if(bflag) {GPIO_SetBits(GPIOB,GPIO_Pin_11);bflag = FALSE;} else {GPIO_ResetBits(GPIOB,GPIO_Pin_11);bflag = TRUE;} //printf("UART SUCCESS!!!"); for(i=0;i
        

中间有两句是PB11的闪烁效果,以显示正在正常工作,最后修改"hw_config.c"中的Joy_State

u8 JoyState(void) { /* "right" key is pressed */ if (GetVolt(After_filter[5])/100>2) { return RIGHT; } /* "left" key is pressed */ if (GetVolt(After_filter[5])/100<1) { return LEFT; } /* "up" key is pressed */ if (GetVolt(After_filter[4])/100>2) { return UP; } /* "down" key is pressed */ if (GetVolt(After_filter[4])/100<1) { return DOWN; } /* No key is pressed */ else { return 0; } }

其中GetVolt是对采样结果进行十进制转化

u16 GetVolt(u16 advalue) { return (u16)(advalue * 330 / 4096); //求的结果扩大了100倍,方便下面求出小数 }

为了让上述程序正常运行,"hw_config.c"中添加外部变量声明:

extern vu16 After_filter[8];
extern u16 GetVolt(u16 advalue);

菜鸟
2014-05-04 22:59 5楼

这楼来更一下串口:

首先串口配置如下


void USART_Configuration(void) //串口初始化函数 { //UART and LED clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO , ENABLE);//打开串口时钟 //GPIOB led GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 ; //管脚位置定义,标号可 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure);//B 组GPIO 初始化 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // no use!!! //UART pins GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//管脚9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//管脚10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//RX初始化 //UART mode USART_InitStructure.USART_BaudRate = 9600; //波特率2400 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字节 USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打开Rx接收和Tx发送功能 USART_Init(USART1, &USART_InitStructure); //初始化 USART_Cmd(USART1, ENABLE); //启动串口 }

上面的配置代码是针对手柄的,其中包含了配置手柄上两个LED的代码,串口的波特率是9600,在调试串口时出了一些问题。见http://forum.eepw.com.cn/thread/250241/1

mian函数和上层一样,main函数其中有一部分代码是让一个led闪烁,这样做的目的是直观的看到机器有没有死机。


飞机上的串口比较蛋疼,因为飞机上的晶振是16M的,所以要配置时钟,串口才能正常,我不会配置(会的大牛求指导啊),我有一个简单的方法,就是配置串口波特率为9600,然后电脑上串口工具使用19200接收,这样完全正常。


菜鸟
2014-05-04 23:34 6楼

这楼把飞机上的代码全部拿出来,重点就是PWM啦,其它的就是串口的问题,上层已经说明,上全部代码

RCC


void RCC_Configuration(void) { /* RCC system reset(for debug purpose) */ RCC_DeInit(); /* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON); /* Wait till HSE is ready */ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) { /* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* Flash 2 wait state */ FLASH_SetLatency(FLASH_Latency_2); /* HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* PCLK2 = HCLK */ RCC_PCLK2Config(RCC_HCLK_Div1); /* PCLK1 = HCLK/2 */ RCC_PCLK1Config(RCC_HCLK_Div2); /* PLLCLK = 8MHz * 9 = 72 MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);//这一句DIV2貌似不管用,对串口没影响 /* 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) { } } RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* GPIOA and AFIO clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);//打开串口时钟 }


所有引脚的配置


void GPIO_Configuration(void) { //GPIOC pin13 normal leds GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //管脚位置定义,标号可 GPIO_Init(GPIOC, &GPIO_InitStructure);//B 组GPIO 初始化 //PWM GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); //UART GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//管脚9 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出 GPIO_Init(GPIOA, &GPIO_InitStructure); //TX初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//管脚10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入 GPIO_Init(GPIOA, &GPIO_InitStructure);//RX初始化 }

UART配置,正如上层说的,波特率配置9600,PC用19200接收才正常,蛋疼



void USART_Configuration(void) //串口初始化函数 { USART_InitStructure.USART_BaudRate = 9600; //波特率2400 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长8位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字节 USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打开Rx接收和Tx发送功能 USART_Init(USART1, &USART_InitStructure); //初始化 USART_Cmd(USART1, ENABLE); //启动串口 }

PWM,借鉴了snake的代码,版权归snake



void PWMchannel_config(int t1,int t2,int t3,int t4) { TIM_TimeBaseStructure.TIM_Period = 665; TIM_TimeBaseStructure.TIM_Prescaler = 10; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = t1; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = t2; TIM_OC2Init(TIM2, &TIM_OCInitStructure); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = t3; TIM_OC3Init(TIM2, &TIM_OCInitStructure); TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = t4; TIM_OC4Init(TIM2, &TIM_OCInitStructure); TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); }

NVIC



void NVIC_Configuration(void) { #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif }

主函数

int main(void) { #ifdef DEBUG debug(); #endif bool bflag = TRUE; u16 value[8]; u8 i; RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); TIM_Cmd(TIM2, ENABLE); USART_Configuration(); while (1) { sleep(0x1EFFFFF); for(i=0;i<8;i++) { value[i]= i; printf("%d.%d\t",value[i]/100,value[i]%100); sleep(0x1EFF); } printf("\n"); if(bflag) {GPIO_SetBits(GPIOC,GPIO_Pin_13);bflag = FALSE; PWMchannel_config(100,100,100,100);} else {GPIO_ResetBits(GPIOC,GPIO_Pin_13);bflag = TRUE; PWMchannel_config(0,0,0,0);} } }

废话不多说,这段程序的效果就是:螺旋桨转一下停一下,灯也一闪一闪的



高工
2014-05-05 13:03 7楼

代码贴了很多,辛苦啦!

把自己的进程记录下来,感觉是不是很好呢

院士
2014-05-05 23:25 8楼

源代码整洁。

值得表扬~~

送上10个积分的奖励

高工
2014-05-06 15:30 9楼
不错不错,顶一个 代码没什么版权,既然贴出来 能被采用是荣幸
院士
2014-05-08 11:27 10楼

楼主 已经将时钟修改了啊!

不知道哪里出了问题!

回头我i把我的工程文件上传一下,供参考

共10条 1/1 1 跳转至

回复

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