我们可以使用Arduino IDE和相关的STM32开发板来进行STM32的开发。STM32是一系列由STMicroelectronics开发的32位ARM Cortex-M微控制器,而Arduino是一个开源电子原型平台,提供了简单易用的开发环境和库函数,因此两者结合可以为开发者提供便利。要在Arduino IDE中使用STM32开发板,首先需要安装STM32的支持库和板支持文件。你可以通过添加额外的硬件支持来安装STM32支持。
在”文件-》首选项-》其他开发板管理器地址“ 添加如下url即可更新STM32的支持包。
https://github.com/stm32duino/BoardManagerFiles/raw/master/package_stmicroelectronics_index.json
更新过程会持续短时间更新完即可使用了。
创建工程后会自动创建如下两个函数由于初始化及循环调用处理,对应的注释能看出这两函数需要填充的内容。
这两个接口是何时被调用的,我们查看stm32 对应的固件代码对应的入口函数就知道了,以上俩函数的调用位置(C:\Users\Administrator\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.7.1\cores\arduino\main.cpp)。
#define ARDUINO_MAIN
#include "Arduino.h"
// Force init to be called *first*, i.e. before static object allocation.
// Otherwise, statically allocated objects that need HAL may fail.
__attribute__((constructor(101))) void premain()
{
// Required by FreeRTOS, see http://www.freertos.org/RTOS-Cortex-M3-M4.html
#ifdef NVIC_PRIORITYGROUP_4
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
#endif
#if (__CORTEX_M == 0x07U)
// Defined in CMSIS core_cm7.h
#ifndef I_CACHE_DISABLED
SCB_EnableICache();
#endif
#ifndef D_CACHE_DISABLED
SCB_EnableDCache();
#endif
#endif
init();
}
/*
* \brief Main entry point of Arduino application
*/
int main(void)
{
initVariant();
setup();
for (;;) {
#if defined(CORE_CALLBACK)
CoreCallback();
#endif
loop();
serialEventRun();
}
return 0;
}
添加测试代码读取I2C寄存器
选择硬件为STM32C031C6,添加如下测试代码访问I2C读取传感器数据。
/*
DigitalReadSerial
Reads a digital input on pin 2, prints the result to the Serial Monitor
This example code is in the public domain.
https://www.arduino.cc/en/Tutorial/BuiltInExamples/DigitalReadSerial
*/
#include <Wire.h>
#define KX224_DEVICE_ADDRESS_1E (0x1E) // 7bit Addrss
#define KX224_DEVICE_ADDRESS_1F (0x1F) // 7bit Address
#define KX224_WAI_VAL (0x2B)
#define KX224_XOUT_L (0x06)
#define KX224_WHO_AM_I (0x0F)
#define KX224_CNTL1 (0x18)
#define KX224_ODCNTL (0x1B)
#define KX224_CNTL1_TPE (1 << 0)
#define KX224_CNTL1_WUFE (1 << 1)
#define KX224_CNTL1_TDTE (1 << 2)
#define KX224_CNTL1_GSELMASK (0x18)
#define KX224_CNTL1_GSEL_8G (0x00)
#define KX224_CNTL1_GSEL_16G (0x08)
#define KX224_CNTL1_GSEL_32G (0x10)
#define KX224_CNTL1_DRDYE (1 << 5)
#define KX224_CNTL1_RES (1 << 6)
#define KX224_CNTL1_PC1 (1 << 7)
#define KX224_ODCNTL_OSA_50HZ (2)
#define KX224_ODCNTL_LPRO (1 << 6)
#define KX224_IIR_BYPASS (1 << 7)
#define KX224_CNTL1_VAL (KX224_CNTL1_RES | KX224_CNTL1_GSEL_8G)
#define KX224_ODCNTL_VAL (KX224_ODCNTL_OSA_50HZ)
unsigned short _g_sens = 4096;
byte kx224_read(unsigned char memory_address, unsigned char *data, int size)
{
byte rc;
unsigned char cnt;
Wire.beginTransmission(KX224_DEVICE_ADDRESS_1E);
Wire.write(memory_address);
rc = Wire.endTransmission(false);
if (rc != 0) {
return (rc);
}
Wire.requestFrom(KX224_DEVICE_ADDRESS_1E, size, true);
cnt = 0;
while(Wire.available()) {
data[cnt] = Wire.read();
cnt++;
}
return (0);
}
byte kx224_write(unsigned char memory_address, unsigned char *data, unsigned char size)
{
byte rc;
Wire.beginTransmission(KX224_DEVICE_ADDRESS_1E);
Wire.write(memory_address);
Wire.write(data, size);
rc = Wire.endTransmission(true);
return (rc);
}
byte kx224_get_rawval(unsigned char *data)
{
byte rc;
rc = kx224_read(KX224_XOUT_L, data, 6);
if (rc != 0) {
Serial.println(F("Can't get KX224 accel value"));
}
return (rc);
}
byte kx224_get_val(float *data)
{
byte rc;
unsigned char val[6];
signed short acc[3];
rc = kx224_get_rawval(val);
if (rc != 0) {
return (rc);
}
acc[0] = ((signed short)val[1] << 8) | (val[0]);
acc[1] = ((signed short)val[3] << 8) | (val[2]);
acc[2] = ((signed short)val[5] << 8) | (val[4]);
// Convert LSB to g
data[0] = (float)acc[0] / _g_sens;
data[1] = (float)acc[1] / _g_sens;
data[2] = (float)acc[2] / _g_sens;
return (rc);
}
// the setup routine runs once when you press reset:
void setup() {
unsigned char reg = 0;
unsigned char rc = 0;
unsigned char gsel;
// initialize serial communication at 9600 bits per second:
Serial.begin(115200);
Wire.begin();
rc = kx224_read(KX224_WHO_AM_I, ®, sizeof(reg));
if (rc != 0) {
Serial.println(F("Can't access KX224"));
Serial.println(rc);
}
Serial.print(F("KX224_WHO_AMI Register Value = 0x"));
Serial.println(reg, HEX);
if (reg != KX224_WAI_VAL) {
Serial.println(F("Can't find KX224"));
return;
}
reg = KX224_ODCNTL_VAL;
rc = kx224_write(KX224_ODCNTL, ®, sizeof(reg));
if (rc != 0) {
Serial.println("Can't write KX224 ODCNTL register");
return;
}
rc = kx224_read(KX224_CNTL1, ®, sizeof(reg));
if (rc != 0) {
Serial.println(F("Can't read KX224 CNTL1 register"));
return;
}
gsel = reg & KX224_CNTL1_GSELMASK;
reg |= KX224_CNTL1_PC1;
rc = kx224_write(KX224_CNTL1, ®, sizeof(reg));
if (rc != 0) {
Serial.println(F("Can't write KX224 CNTL1 register at second"));
return;
}
switch(gsel) {
case KX224_CNTL1_GSEL_8G :
// (Equivalent counts) / (Range) = (32768 / 8)
_g_sens = 4096;
break;
case KX224_CNTL1_GSEL_16G :
// (Equivalent counts) / (Range) = (32768 / 16)
_g_sens = 2048;
break;
case KX224_CNTL1_GSEL_32G :
// (Equivalent counts) / (Range) = (32768 / 32)
_g_sens = 1024;
break;
default:
break;
}
}
// the loop routine runs over and over again forever:
void loop() {
byte rc;
float acc[3];
rc = kx224_get_val(acc);
if (rc == 0) {
Serial.write("KX224 (X) = ");
Serial.print(acc[0]);
Serial.println(" [g]");
Serial.write("KX224 (Y) = ");
Serial.print(acc[1]);
Serial.println(" [g]");
Serial.write("KX224 (Z) = ");
Serial.print(acc[2]);
Serial.println(" [g]");
Serial.println();
}
delay(500);
}
setup 函数内添加串口波特率设置及KX224传感器参数配置,loop 接口内周期读取传感器数据并打印。固件的I2C接口使用的GPIO端口是多少,这个从固件库的配置文件(C:\Users\Administrator\AppData\Local\Arduino15\packages\STMicroelectronics\hardware\stm32\2.7.1\variants\STM32C0xx\C031C(4-6)(T-U)\variant_NUCLEO_C031C6.h)中找到答案,默认使用的是PB8/9这组,理论上用户也可以根据自己的配置定义该引脚。
// On-board LED pin number
#define LED_GREEN PA5
#ifndef LED_BUILTIN
#define LED_BUILTIN LED_GREEN
#endif
// On-board user button
#ifndef USER_BTN
#define USER_BTN PC13
#endif
// I2C Definitions
#ifndef PIN_WIRE_SDA
#define PIN_WIRE_SDA PB9
#endif
#ifndef PIN_WIRE_SCL
#define PIN_WIRE_SCL PB8
#endif
按照此定义连接开发板和传感器。
上电验证
晃动传感器发现读取的数据会根据角度的不同发生变化,说明已经正常读取到传感器的数据。