本帖最后由 Ketose 于 2017-8-19 11:19 编辑
二姨家的活动一定要参加。NuTiny-SDK-M0518S 这个板子还是二姨家搞活动送的,基本上属于最小开发板了,板子上自带Nu-Link。趁这次活动,把这个小开发板拿出来又玩一下。先看下M058SSAN的资源
M058S为Cortex™-M0 32位微控制器系列,其特点为宽电压工作范围2.5V至.5V与-40℃ ~ 85℃工作温度、内建22.1184 MHz高精度RC晶振(±1%精确度,25℃ 5V)、并内建Data Flash、欠压检测、丰富周边、整合多种多组串行传输接口、高抗干扰能力(8KV ESD/4KV EFT)、支持在线系统更新(ISP)、在线电路更新(ICP)与在线应用程序更新(IAP),提供封装有QFN33、LQFP48与LQFP64。 关键特性 : • 内核(Core) - Cortex™-M0 32位微处理器 - 工作频率可达 50 MHz - 工作电压:2.5V to 5.5V - 工作温度:-40℃ ~ 85℃ • 内存(Memory) - 32 KB应用程序 - 内嵌4 KB SRAM - 内嵌4 KB Data Flash - 在线系统更新ISP(In-System Programming) - 在线电路更新ICP(In-Circuit Programming) - 在线应用程序更新 IAP(In-Application Programming) • 模拟转数字转换器(ADC) - 提供8通道 - 12位分辨率 - 每秒采样率可达 800kSPS - 提供误差±1℃温度传感器 | • 脉波宽度调变(PWM) - 最多4通道PWM输出或互补式PWM输出 • 通讯接口(Connectivity) - 一组SPI(可达36 MHz) - 2组I²C(可达 400 kHz) - 一组UART • 时钟控制(Clock control) - 外部晶振4 to 24 MHz - 内置22.1184 MHz高精度RC晶振,常温5V下±1%误差
| 板子实物图:
主要是M058S通过I2C总线读MPU6050的数据(x,y,z三个坐标轴的加速度数据和角速度数据),然后把它通过串口显示出来,先看下显示效果,为了好看些,加了些修饰。
因为加入了中文,这个串口显示,时不时的要给我乱码。
如果下图:
所以干脆自己用C#写了一个...
下面说下过程,新唐的SDK里BUG很多,大家用的时候要小心哦。首先用新唐的NuTool-ClockConfigure图形化的配工具来生成MCU的时钟系统初始化代码。
步骤1:选择外部晶振,这里是12M
步骤2:设置PLL时钟频率50MHZ,选择第一项目,其它的也可以。
步骤3:设置系统时钟
步骤4:配置使用到的外设的时钟。UART要使用HIRC 22.1184MHZ做为时钟源。其它用到哪个选哪个。
以后配置完成后,生成时钟初始化代码,命 名这clock_init.c,这个生成的代码就有问题,如下图
这个函数在最新的M058S的SDK里是没有的,最后我在M0546的SDK里找到相应的代码,把它移植M058S里来,看了参考手器,应该是没有问题,使用过程也没有什么问题。(这个应该是M058S的BUG)
接下来使用NuTool-PinConfigure配置外设:使用了UART和I2C0,如图所示
配置完后生成外设初始化代码。
项目中使用了I2C总线,在使用M058S的SDK的I2C操作的SDK里也有BUG。如下:
这个计算公式是错误的,至少我用实验了是不对的。使用这个函数I2C总结是没法工作。(I2C_Open(I2C_T *i2c, uint32_t u32BusClock)这个BUG害人不浅)
参考手册上是这么写的,按这个计算出I2CLK的值才是正确的。
还要吐槽下,从新唐官网上下载了最新的Nu-Link_Keil_Driver_V2.02.6629这个也更坑,安装上这个以后Keil里调试时查看外设寄存器全乱了。。。还是看图吧。
所有的寄存器都用P0代表了,请问下新唐,我想看P1怎么办?
好下,我发现的BUG就这些了,下面上代码
main.c
#include "M058S.h" // Device header
#include "stdio.h"
#include "mpu6050.h"
/*----------------------------------------------------------------------------
初初化函数
*----------------------------------------------------------------------------*/
extern void SYS_Init(void);
extern void Uart_Init(void);
extern void GPIO_Init(void);
extern void Timer_Init(void);
void wait_us(uint32_t us);
void wait_ms(uint32_t ms);
void wait_s(uint32_t s);
void WorkOut(void);
/*
* [url=home.php?mod=space&uid=247401]@brief[/url] 主函数
* @param 无
* [url=home.php?mod=space&uid=266161]@return[/url] 退出代码
*/
int main(void)
{
SYS_Init();
GPIO_Init();
Uart_Init();
Timer_Init();
InitMPU6050();
while(1)
{
WorkOut();
wait_s(1);
}
}
/*
* [url=home.php?mod=space&uid=247401]@brief[/url] 工作输出
* @param 无
* [url=home.php?mod=space&uid=266161]@return[/url] 无
*/
void WorkOut()
{
printf("begin");
printf("┌───────────────────────────────────┐");
printf("│ 八月,新唐你好! │");
printf("│ Hello, 21ic.com ! │");
printf("│ │");
printf("│ Read the MPU6050 test using the I2C bus. │");
printf("│ 加速度:X=%04d,Y=%04d,Z=%04d │",GetAccelValue('x'),GetAccelValue('y'),GetAccelValue('z'));
printf("│ 角速度:X=%04d,Y=%04d,Z=%04d │",GetGyroValue('x'),GetGyroValue('y'),GetGyroValue('z'));
printf("│ │");
printf("│ MyID:Ketose │");
printf("└───────────────────────────────────┘");
uint8_t c = 0x1A;
UART_Write(UART0,(uint8_t*)&c,1);
}
/*
* [url=home.php?mod=space&uid=247401]@brief[/url] 延时函数
* @param 秒
* [url=home.php?mod=space&uid=266161]@return[/url] 无
*/
void wait_s(uint32_t s)
{
for(int i=s;i>0;i--)
{
wait_ms(1000);
}
}
/*
* [url=home.php?mod=space&uid=247401]@brief[/url] 延时函数
* @param 毫秒
* [url=home.php?mod=space&uid=266161]@return[/url] 无
*/
void wait_ms(uint32_t ms)
{
for(int i=ms;i>0;i--)
{
wait_us(1000);
}
}
/*
* [url=home.php?mod=space&uid=247401]@brief[/url] 延时函数
* @param 微秒
* [url=home.php?mod=space&uid=266161]@return[/url] 无
*/
void wait_us(uint32_t us)
{
CLK_SysTickDelay(us);
}
mpu6050.c
#include "MPU6050.h"
extern void wait_ms(uint32_t us);
//各坐标轴上静止偏差(重力,角速度)
int16_t offsetAccelX = 17;
int16_t offsetAccelY = -70;
int16_t offsetAccelZ = 16474;
int16_t offsetGyroX = 11;
int16_t offsetGyroY = 38;
int16_t offsetGyroZ = 3;
void i2c_write(uint8_t Register,uint8_t data)
{
i2c_WriteByte(SlaveAddress,Register,data);
}
uint8_t i2c_read(uint8_t Register)
{
return i2c_ReadByte(SlaveAddress,Register);
}
#define Single_WriteI2C i2c_write
#define Single_ReadI2C i2c_read
//**************************************
//初始化MPU6050
//**************************************
void InitMPU6050()
{
i2c_init();
Single_WriteI2C(PWR_MGMT_1, 0x80); //复位MPU6050
wait_ms(10);
Single_WriteI2C(PWR_MGMT_1,0X00); //唤醒MPU6050
wait_ms(10);
Single_WriteI2C(SMPLRT_DIV, 0x07);
wait_ms(10);
Single_WriteI2C(CONFIG, 0x06);
wait_ms(10);
Single_WriteI2C(GYRO_CONFIG, 0x18);
wait_ms(10);
Single_WriteI2C(ACCEL_CONFIG, 0x01);
wait_ms(10);
}
//**************************************
//合成数据
//**************************************
int16_t GetMPUOutValue(uint8_t REG_Address)
{
int16_t result;
uint8_t H,L;
H=Single_ReadI2C(REG_Address);
L=Single_ReadI2C(REG_Address+1);
result = (H<<8)+L;
return result; //合成数据
}
//**************************************
//取某一轴上的加速度数据
//**************************************
int16_t GetAccelValue(char axis)
{
int16_t result = 0;
switch(axis)
{
case 'x':
case 'X':
{
result = GetMPUOutValue(ACCEL_XOUT_H) - offsetAccelX;
}
break;
case 'y':
case 'Y':
{
result = GetMPUOutValue(ACCEL_YOUT_H) - offsetAccelY;
}
break;
case 'z':
case 'Z':
{
result = GetMPUOutValue(ACCEL_ZOUT_H) - offsetAccelZ;
}
break;
}
return result;
}
//**************************************
//取某一轴上的角速度数据
//**************************************
int16_t GetGyroValue(char axis)
{
int16_t result = 0;
switch(axis)
{
case 'x':
case 'X':
{
result = GetMPUOutValue(GYRO_XOUT_H) - offsetGyroX;
}
break;
case 'y':
case 'Y':
{
result = GetMPUOutValue(GYRO_YOUT_H) - offsetGyroY;
}
break;
case 'z':
case 'Z':
{
result = GetMPUOutValue(GYRO_ZOUT_H) - offsetGyroZ;
}
break;
}
return result;
}
i2c_api.c
/**************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url] i2c_api.c
* [url=home.php?mod=space&uid=895143]@version[/url] V1.0
* $Revision: 2 $
* $Date: 17/08/03 7:08p $
* [url=home.php?mod=space&uid=247401]@brief[/url] M058S SPI hardware abstract layer API implemented.
*
* @note
* Copyright (C) 2017 sunsjw All rights reserved.
*
******************************************************************************/
#include
#include
#include
extern void wait_us(uint32_t us);
#define I2Cx I2C0
#define WRITE 0
#define READ 1
//**************************************
//I2C总线初始化
//**************************************
void i2c_init(void)
{
SYS->P3_MFP |= (SYS_MFP_P34_SDA0|SYS_MFP_P35_SCL0);
SYS_ResetModule(I2C0_RST);
I2C_Open(I2Cx,400000);
I2C0->I2CLK = 124;
}
//**************************************
//向I2C设备写入一个字节数据
//**************************************
void i2c_WriteByte(uint8_t SlaveAddr,uint8_t REG_Address,uint8_t REG_data)
{
I2C_START(I2Cx);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x08);
I2C_SetData(I2Cx,(SlaveAddr<<1)+WRITE);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x18);
I2C_SetData(I2Cx,REG_Address);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x28);
I2C_SetData(I2Cx,REG_data);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x28);
I2C_STOP(I2Cx);
wait_us(100);
}
//**************************************
//从I2C设备读取一个字节数据
//**************************************
uint8_t i2c_ReadByte(uint8_t SlaveAddr,uint8_t REG_Address)
{
I2C_START(I2Cx);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x08);
I2C_SetData(I2Cx,(SlaveAddr<<1)+WRITE);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x18);
I2C_SetData(I2Cx,REG_Address);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x28);
I2C_START(I2Cx);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x10);
I2C_SetData(I2Cx,(SlaveAddr<<1)+READ);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x40);
I2C_SET_CONTROL_REG(I2Cx,I2C_I2CON_SI);
I2C_WAIT_READY(I2Cx);
while(I2C_GetStatus(I2Cx) != 0x58);
uint8_t result = I2C_GetData(I2Cx);
I2C_STOP(I2Cx);
return result;
}
//**************************************
//从I2C设备读取指定长度字节数据
//**************************************
int i2c_ReadBytes(int dev_address,int reg_address,char* buffer,int length)
{
return 0;
}
//**************************************
//向I2C设备写入多字节数据
//**************************************
int i2c_WriteBytes(int dev_address,int reg_address,char* buffer,int length)
{
return 0;
}
这个项目借鉴了MBed驱动的一些思想,把I2C总线抽象出来,MPU6050的驱动只使用I2C的抽象API,不同的平台只需要实现I2C的抽象API就可以了。最上再传个我自己SuperCom的动画效果图。
有需要的同学可以私聊我。
|