三、程序讲解 硬件调试:大家拿到套件后,请根据原理图进行焊接,芯片方向要注意,不清楚的找楼主要高清大图,按照图片焊接也挺简单.完全都是贴片的元件,考验大家的焊工
焊接好后,就要开始软件调试了,这里才是四轴最"好玩"的地方,当初决定玩四轴也是因为这个,因为四轴硬件简单,主要拼的是软件,不像直机什么的,硬件太复杂了.
软件的调试,建议大家还是一步一步来.虽然我开源了飞控的全部程序,大家烧进去就可以实现基本的飞行了,但是我们自己做飞控最关键的就是程序了,直接copy一个工程过来,想必大家直接消化还是很不容易的.就像学习骑车一样,还不会走路,就学骑自行车,怎么会骑好.所以还是建议大家从基础的开始.
从哪里开始呢,因为我们使用的是stm32f103,大家就从最简单的stm32的驱动开始吧.
以下都是针对我的飞控板写的,大家如果用的自己的,记得需要把IO和端口都改为自己的
stm32可以说就是飞控的大脑,mpu6050和hmc5883就是飞控的眼睛,耳朵.飞控的所有功能,都是通过stm32实现的,所以大家清楚了stm32做什么了以后,就要好好的把他驱动好,让他按照我们的想法来运转,这样飞控才能好好的工作.
1、点亮LED 首先下载我们需要的软件环境,就是MDK (KEIL FOR ARM),我用的是4.7版本,有了自动补全功能,挺好用.当然,还要有个JLINK,使用swd方式进行调试.然后就可以开始第一步的程序编写了.按照网上的教程,使用库函数建立一个空白的工程,从最简单的,点亮一个LED开始.
要点亮一个led,也不是一件简单的事情,首先,系统时钟要配置好(最新库函数在初始化时已经帮我们把时钟初始化好了,不用我们再初始化了,当然,除非你有特殊要求),然后要配置端口的输入输出,还要打开响应端口的外设时钟.
- void LED_INIT(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure; 这个是端口配置结构体
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); 打开外设GPIOB的时钟,因为LED是通过GPIOB的9,11,14,15来驱动的
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_9 ; 选择响应的管脚
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 设置IO速度
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 设置IO驱动方式,out为输出,PP为推挽输出
- GPIO_Init(GPIOB, &GPIO_InitStructure); 对GPIOB进行初始化
- }
[color=rgb(49, 132, 219) !important]复制代码
初始化好了,再写几个函数来操作LED,更加方便
- #define LED1_OFF GPIO_SetBits(GPIOB, GPIO_Pin_11)
- #define LED1_ON GPIO_ResetBits(GPIOB, GPIO_Pin_11)
- #define LED2_OFF GPIO_SetBits(GPIOB, GPIO_Pin_14)
- #define LED2_ON GPIO_ResetBits(GPIOB, GPIO_Pin_14)
- #define LED3_OFF GPIO_SetBits(GPIOB, GPIO_Pin_15)
- #define LED3_ON GPIO_ResetBits(GPIOB, GPIO_Pin_15)
- #define LED4_OFF GPIO_SetBits(GPIOB, GPIO_Pin_9)
- #define LED4_ON GPIO_ResetBits(GPIOB, GPIO_Pin_9)
- #define LEDALL_OFF GPIO_SetBits(GPIOB, GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_9)
- #define LEDALL_ON GPIO_ResetBits(GPIOB, GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15 | GPIO_Pin_9)
[color=rgb(49, 132, 219) !important]复制代码
本小编附上新版F4版LED函数:- #define LED5(x) x ? GPIO_ResetBits(GPIOE,GPIO_Pin_0): GPIO_SetBits(GPIOE,GPIO_Pin_0)
- #define LED6(x) x ? GPIO_ResetBits(GPIOE,GPIO_Pin_1): GPIO_SetBits(GPIOE,GPIO_Pin_1)
- #define LED7(x) x ? GPIO_ResetBits(GPIOE,GPIO_Pin_2): GPIO_SetBits(GPIOE,GPIO_Pin_2)
- #define LED8(x) x ? GPIO_ResetBits(GPIOE,GPIO_Pin_3): GPIO_SetBits(GPIOE,GPIO_Pin_3)
- #define LED1(x) x ? GPIO_ResetBits(GPIOE,GPIO_Pin_4): GPIO_SetBits(GPIOE,GPIO_Pin_4)
- #define LED2(x) x ? GPIO_ResetBits(GPIOC,GPIO_Pin_13): GPIO_SetBits(GPIOC,GPIO_Pin_13)
- #define LED3(x) x ? GPIO_ResetBits(GPIOC,GPIO_Pin_14): GPIO_SetBits(GPIOC,GPIO_Pin_14)
- #define LED4(x) x ? GPIO_ResetBits(GPIOC,GPIO_Pin_15): GPIO_SetBits(GPIOC,GPIO_Pin_15)
[color=rgb(49, 132, 219) !important]复制代码
这几个函数功能很简单,就是对IO的输出电平进行操作.当LED可以点亮后,更高级的比如LED的闪烁,就需要大家自己写了,实现的方法很多,可以用循环实现,也可以用定时中断实现.选用哪种方式实现,就要看具体的使用地点和情况了.
2、驱动串口 第一步LED驱动好了,下一步做点什么呢?就来驱动下串口吧,串口还是调试时一个很好用的工具.
串口,在我们这个工程里,其实就是用来调试的,无线控制是通过SPI来进行,其实无线调试好以后,串口也就没有用了,可以使用无线进行调试的,这样更加方便.其实串口是完全可以省略的.
那么怎么使用这个串口呢?串口可以理解为一根网线,通过他,可以将飞机上的数据传输到电脑上,就这么简单.........至于传什么,怎么传,学问就大了....
串口驱动好以后,可以帮助我们分析很多问题,有些甚至JLINK也做不到,观察变量,观察标志位,观察程序运行状态,等等,都可以通过串口来实现,上位机为了配合串口和无线调试,还特意做了一个DEBUG功能,就是为了帮助大家更方便的调试,可以通过串口发送一个自定义的命令,打开上位机的LED,或者改变上位机显示的寄存器数字.这样可以帮助大家知道程序的执行状态,比如中断进入没进入啊,进入的频率啊,变量现在的值是多少啊等等信息.
我这里仅仅是一点点自己的调试经验,至于怎么发送,发送一个什么样的格式,大家个人习惯不同,写出来当然也各不相同,有人喜欢用printf,我就喜欢十六进制,各有长短
串口调试也一样,第一步,当然是初始化. - void USART1_INIT(void)
- {
- USART_InitTypeDef USART_InitStructure;
- USART_ClockInitTypeDef USART_ClockInitStruct;
- GPIO_InitTypeDef GPIO_InitStructure;
[color=rgb(49, 132, 219) !important]复制代码
串口初始化好了,就要测试收发了,将串口用串口线和电脑连接起来,先来简单的发送,用上位机看看能不能收到数据. 对了 !这里还要设置串口中断
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
- 我用的第二组,串口给了优先级3,subfriority3
- 串口中断函数:
- void USART1_IRQHandler(void)
- {
- USART1_IRQ();
- }
- void USART1_IRQ(void)
- {
- if(USART_GetITStatus(USART1,USART_IT_TXE)!=RESET)
- {
- 发送中断
- }
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
- {
- 接收中断
- }
- }
[color=rgb(49, 132, 219) !important]复制代码
中断也写好后,基本的发送接收应该就没问题了.
但是在使用过程中,没有一个缓冲区肯定是不行的,关于这方面的帖子很多,大家在论坛上搜索下吧.我就简单介绍下我用的简单的环形缓冲吧.
我用了一个环形发送缓冲,比如一个长度为100字节的数组,再定义两个变量,比如num与t_num
num表示缓冲区内下一个空字节在第几字节,t_num表示下一个需要发送的字节在缓冲区的多少字节 比如需要发送12345 这5个数字,分别写入数组的01234字节,共5字节,此时num+=5,表示buf[5]是空的.写入数据后,激活发送,发送完一个字节,t_num+1,并判断t_num与num的大小,如果t_num<num,就急需发送,如果t_num=num,说明数据已经发送完了.
大致意思就是这样.
|