上次用stm32cubemx生成了L053R8的一些基础程序,现在就来进行一些改动和添加,那么改动的程序应该添加到哪里呢,大家看一下生成的函数,发现有这个注释:
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
类似于这种的,有BEGIN和END的,把要添加的函数放在这中间,这样的话,假如想重新配置cubemx,那么重新生成的函数就不会覆盖把它覆盖掉。
当然了首先需要配置一下串口的printf,这个就不用多说了,找到usart.c文件添加这个函数:
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART2 and Loop until the end of transmission */
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
当然了,也并不仅仅局限于这种,还有很多种,无非就是重定向罢了,然后在h文件里声明一下,这时回到main函数,再写个printf函数用串口直接就可以打印了,所以说用cubemx很方便的。
既然串口配置完了,那么接下来要做的就是iic的修改了,在官方给的例程当中,只需要修改它的初始化数据和iic读取以及写入,那么来看看官方的例程:
//************初始化L3G4200D的加速度*********************************
void LSM303A_Init( void )
{
I2C_WriteOneByte(I2C1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG1, 0x37);
I2C_WriteOneByte(I2C1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4, 0x00);
}
//************初始化L3G4200D的磁感应*********************************
void LSM303M_Init( void )
{
I2C_WriteOneByte(I2C1,LSM303M_I2C_ADDR,LSM303M_CRB_REG, 0xa0);
I2C_WriteOneByte(I2C1,LSM303M_I2C_ADDR,LSM303M_MR_REG, 0x00);
}
楼主找了一下HAL库里面,没有这个函数,那么需要替换掉,进入到HAL的iic库中,可以看到这个函数:
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
对,就是这个,不过可能有人疑惑了,怎么有7个形参?官方里面只有四个啊,对此不用太在意,可以看一下上面的注释,翻译一下会发现有几个没什么用,楼主就不一样样详解了,直接改动代码:
//************初始化L3G4200D的加速度*********************************
void LSM303A_Init( void )
{
uint8_t data;
data = 0x37;
HAL_I2C_Mem_Write(&hi2c1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG1,1,&data,1,35);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4,1,&data,1,35);
}
//************初始化L3G4200D的磁感应*********************************
void LSM303M_Init( void )
{
uint8_t data;
data = 0xa0;
HAL_I2C_Mem_Write(&hi2c1,LSM303M_I2C_ADDR,LSM303M_CRB_REG,1, &data,1,35);
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1,LSM303M_I2C_ADDR,LSM303M_MR_REG,1, &data,1,35);
}
这个就是改动之后的write函数,但是iic可不止write,还有read呢,看一下官方的read函数,由于是分开的,楼主给它们合在了一起:
I2C_Read(I2C1,LSM303M_I2C_ADDR,LSM303M_OUT_X_H,buffer,6);//|0x80
I2C_Read(I2C1,LSM303M_I2C_ADDR,LSM303M_CRB_REG,&f,1);
I2C_Read(I2C1,LSM303A_I2C_ADDR,LSM303A_OUT_X_L|0x80,buffer,6);
I2C_Read(I2C1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4|0x80,ctrlx,2);
I2C_Read(I2C1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4,ctrlx,2);
Ok,综合起来就是上面五个,同样的,HAL库里面没有这个函数,老样子,
在iic库里面,找到这个函数:
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
其实就在write的下面而已,改动一下:
HAL_I2C_Mem_Read(&hi2c1,LSM303M_I2C_ADDR,LSM303M_OUT_X_H,1,buffer,6,35);//|0x80
HAL_I2C_Mem_Read(&hi2c1,LSM303M_I2C_ADDR,LSM303M_CRB_REG,1,&f,1,35);
HAL_I2C_Mem_Read(&hi2c1,LSM303A_I2C_ADDR,LSM303A_OUT_X_L|0x80,1,buffer,6,35);
HAL_I2C_Mem_Read(&hi2c1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4|0x80,1,ctrlx,2,35);
HAL_I2C_Mem_Read(&hi2c1,LSM303A_I2C_ADDR,LSM303A_CTRL_REG4,1,ctrlx,2,35);
至此,关于LSM303iic的协议改动完成了,回到主函数,官方里面有这个代码:
float buf_A[3],buf_M[3];
float north,first_north;
char flag;
uint16_t n = 100;
void Delay(uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
void Date_AM()
{
LAM303M_Raed(buf_M);
LAM303A_Raed(buf_A);
north=Data_conversion(buf_A,buf_M);
printf("X_A=%f m/s^2\r\n",buf_A[0]);
printf("Y_A=%f m/s^2\r\n",buf_A[1]);
printf("Z_A=%f m/s^2\r\n",buf_A[2]);
printf("X_M=%f T\r\n",buf_M[0] );
printf("Y_M=%f T\r\n",buf_M[1]);
printf("Z_M=%f T\r\n",buf_M[2]);
printf("north=%f degree \r\n",north);
printf("\r\n");
}
至此,用串口就可以打印出所有的数据了。
其实最开始的时候,楼主没有打算用电子罗盘LSM303(因为当时没买),当时手上有一个MPU6050,是原来参加电赛留下来的东西,用F103的板子,也弄出了旋转改变亮度的效果,但是算法相当复杂,用到了DMP四元数和角速度积分以及欧拉角的算法(毕竟MPU6050大多时候用来测翻滚角和俯仰角的,用来测旋转角度也就是偏航角那么算法就更加复杂,)后来在移植到L053的板子上时出现了困难,因为初次接触HAL库,很多地方完全不了解,所以最后迫不得已还是买了电子罗盘,不过电子罗盘就简单多了,毕竟它的老本行就是测角度,没有复杂的算法。
至此,电子罗盘的部分算是完成了,下一步,就是那个pwm灯了。
打开tim.c那个文件夹,cubemx已经把所有的配置都写好了。在最下面添加一段代码:
void USER_PWM_SetDutyRatio(TIM_HandleTypeDef *htim,uint32_t Channel,uint8_t value)
{
TIM_OC_InitTypeDef sConfigOC;
uint32_t period=htim->Init.Period+1;
uint32_t pluse=(value * period)/100;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = pluse;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(htim, &sConfigOC, Channel);
HAL_TIM_PWM_Start(htim, Channel);
}
其中第一个形参代表定时器型号,第二个则是定时器通道,第三个是占空比,满值是100。然后在tim.h文件里声明一下这个函数,可以在main函数的while循环里面添加这个函数,例如:
USER_PWM_SetDutyRatio(&htim2,TIM_CHANNEL_2,n);
然后将RGB全彩灯盘连上对应的引脚就可以观察到亮度变化,当然了,前提是设定一个占空比,后期这个占空比可以通过电子罗盘的数据变化来变化,只要数值赋值给一个变量就是了。
对于这个部分。楼主也是上传了视频,都是用这个教程里的方法来写的。大家可以看看。
视频链接:
http://v.youku.com/v_show/id_XMzgyMjExMzE2OA==.html?spm=a2h0j.11185381.listitem_page1.5!5~A
到此,代码部分已经讲解完毕了,大家可以根据这个代码好好看看,至于代码里面注释的部分是后期用手机app控制的通信协议部分
(图片上就是app 的界面图)
如果对app控制感兴趣的人比较多,楼主可以考虑放出教程。
给大家看看实物图,手机像素不高,大家见谅一下。
大家也看到了。电源就是一个硕大的充电宝,不过挺好用,电量充足。下面那个则是传说中的秘密武器了——旋转灯座,可以转动它来改变亮度,
可能有人会问了,充电宝对面的那两个模块是什么?那个绿色的是扩展的VCC GND 接口。而那个黑色的则是后期添加的东西,一个ESP8266的模块,里面有通信协议,就是通过它来进行手机软件控制的,看起来很高大上的样子,当然了。老样子,大家可以看看演示视频,有app控制灯的颜色的说明。
演示视频链接:
http://v.youku.com/v_show/id_XMzgyMjExMzQ2OA==.html?spm=a2h0j.11185381.listitem_page1.5!6~A
最后,希望每一个人都能做出来旋转灯,甚至是智能旋转灯!!
最终程序:LSM3031.rar