I needed help with running a stepper motor using Codewarrior and a Dragon 12 boa
ID: 3603044 • Letter: I
Question
I needed help with running a stepper motor using Codewarrior and a Dragon 12 board.
I have the keypad code, LCD code, and a main file which you can use to test the other 2 files, but I am struggling on how to write a C code to interact with the stepper motor and implement that into the main file.
[Main.C]
//The project has two device drivers: one for the keypad and other for the LCD
//You need to write your a device driver that will control the stepper motor
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include"Keypad.h"
#include "LCD.h"
#define EDIT_COL 810
char buf[8];
int bufp;
void just_demo(void);
void delay_ms(unsigned);
void main(void) {
char k;
int i;
Keypad_init();
LCD_init();
LCD_setCursor(0,0);
LCD_print("Enter Pos:");
LCD_setCursor(1,0);
LCD_print("Curr Pos:");
LCD_setCursor(1,EDIT_COL);
LCD_print("Stop."); // assume stopped & at pos = 0
for(;;) {
//read the command position from user...
//first put the cursor there so that we print as user is entering keys...
LCD_setCursor(0,EDIT_COL);
//next: keep reading until user press '#' which is key E in this board
//store in buffer & display on LCD what user is entering
//we will assume correct entry
bufp = 0;
k = Keypad_wait_keypress();
while( k!= 0x0E && bufp < 8 ){
buf[bufp++] = k; // store pressed key in buffer
LCD_putchar(k+'0'); //display as user is entering
Keypad_wait_keyup(); //wait until user release this key
k = Keypad_wait_keypress(); //read next key and back to check...
}
//your code should begin here...
//buf has the commanded position and bufp is their count
//move the stepper to that angle given its current position.....
just_demo();
//The stepper should have reached its commanded pos now....
//display curr pos
LCD_setCursor(1,EDIT_COL);
for(i = 0;i < bufp ; i++)
LCD_putchar(buf[i]+'0');
//erase old commanded pos
LCD_setCursor(0,EDIT_COL);
LCD_print(" ");
}
}
void just_demo(){
int i;
for( i = 0; i < 5 ; i++){
LCD_setCursor(1, EDIT_COL);
LCD_print("Mot...");
delay_ms(500);
LCD_setCursor(1, EDIT_COL);
LCD_print(" ");
delay_ms(500);
}
}
/*----------------------------------
;
; delay for 1 us
*/
void delay_1us(){
asm{
PSHX
LDX #4
L1: DBNE X,L1
PULX
}
}
/*------------------------------------------------
; delay_us
------------------------------------------------*/
void delay_us(unsigned int us ){
asm{
pshd
dd: JSR delay_1us
DBNE D, dd
puld
}
}
/*-------------------
; delay_ms
;----------------------------- */
void delay_ms(unsigned int ms){
asm{
pshd
; 2 clock cycles
PSHX ; 2 clock cycles
OutLoop:
LDX #7993 ; 2
InLoop:
DBNE X, InLoop ; 3/3 ( 3 cycles both ways)
DBNE D, OutLoop ; 3/3
PULX ; 3
puld
}
}
[Keypad.C]
#include "keypad.h"
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
void delay_us(unsigned int);
void delay_ms(unsigned int);
// Keypad Device Driver
int col, row;
/*-------------------------------------------------------------
; Keypad_init
; The Keypad on the dragon12 board is connected to port A
; configure port A pins as input & enable the internal pullup registers on them
-----------------------------------------------------------------*/
void Keypad_init(){
DDRA = 0;
PUCR |= 1 ; //Pull-Up Port A Enable
PORTA = 0; //PAx would be driven low once we change its direction in DDRAx to be an output pin
}
/*---------------------------------------------------------------------------
; Keypad_non_scan
; returns the hex code of the currently pressed key, or return $10 if all keys are up
;
; This function does not scan all rows and columns. Instead it accesses the key (if any) in just two quick steps:
; 1. Makes all rows outputs (driven low) and cols as inputs.
; It then reads the cols from PORTA
; 2. It changes the direction of rows as inputs and cols as outputs (driven low).
; It then reads rows from PORTA
; with the row and the col, we do some lookup to find the pressed key or $10
;
----------------------------------------------------------*/
//rows:PORTA[7:4] cols:PORTA[3:0]
char Keypad_non_scan(){
extern char keys[][5];
extern char row_col_tab[];
// rows are out, cols are in
DDRA = 0xF0;
// wait few cycles as noted in the manual
delay_us(5);
//get col: $xE(leftmost column), $xD, $xB, $x7, or $xF if no press
col = PORTA & 0x0F;
//rows are ins, cols are outs
DDRA = 0x0F;
//wait few cycles as noted in the manual
delay_us(5);
//get row: $Ex (first row), $Dx, $Bx, $7x, or $Fx if no press
row = (PORTA >> 4) &0x0F;
//map them into values between 0 & 4
row = row_col_tab[row]; // now could be any value from 0 through 4
col = row_col_tab[col]; // so does col
return keys[row][col];
}
/*------------------------------------------------------------------------------------------
; Keypad_read;
; This is a debounced function
; It keeps sampling the keypad every 5ms until the three samples are same
;
; return the pressed hex key, or $10 if all keys are up (debounced)
-------------------------------------------------*/
char Keypad_read(){
char k[3];
do{
//first sample
k[0]=Keypad_non_scan();
delay_ms(5);
//2nd sample
k[1]=Keypad_non_scan();
delay_ms(5);
//third sample
k[2]=Keypad_non_scan();
}while(k[0] != k[1] || k[1]!=k[2]); // keep sampling until the 3 samples are same
//either the pressed key or 0x10 (debounced)
return k[0];
}
/*----------------------------------------------------
; Keypad_wait_keypress:
; wait until a key is pressed and return
--------------------------------------------------*/
char Keypad_wait_keypress(){
char key;
for( key = Keypad_read() ; key ==0x10; key = Keypad_read() ) //keep trying until a key is pressed
;
return key;
}
/*--------------------------------------------------
; Keypad_wait_keyup:
; wait until all keys are up and then return
-------------------------------------------------------*/
void Keypad_wait_keyup(){
while( Keypad_read() != 0x10 ) //keep trying until all keys are up
;
}
//---------------------------------------
// lookup the key by row & col
//col 0 1 2 3 4
// PA0 PA1 PA2 PA3
//
// row
char keys[][5]={
{0x01, 0x02, 0x03, 0x0A ,0x10}, // 0 PA4
{0x04, 0x05, 0x06, 0x0B ,0x10}, // 1 PA5
{0x07, 0x08, 0x09, 0x0C ,0x10}, // 2 PA6
{0x0F, 0x00, 0x0E, 0x0D ,0x10}, // 3 PA7
{0x10, 0x10, 0x10, 0x10, 0x10} // 4
};
/*----------------------------------------------------------
; lookup the row or the col by the value that is read from PORTA during Keypad_non_scan
;
; when a key is detected, the 4-bit value read from PORTA could be 7, B, D, E. Otherwise, it is F
; We map the detected 4-bit value into row or col:0-3. F will be mapped into 4
*/
char row_col_tab[]={
4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 2, 4, 1, 0, 4
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
};
[LCD.C]
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include "LCD.h"
void delay_ms(unsigned), delay_us(unsigned);
#define E 2
#define RS 1
void lcd_send_nibble(char c);
void lcd_send_data(unsigned char data);
void lcd_send_cmd(unsigned char cmd);
/*----------------------------------------------------------
; LCD connections to MCU
; LCD MC9S12DG256x
; === ============
; RS <----> PK0 RS = 0 for lcd commands transfer, RS=1 for lcd data transfer
;
; E <----> PK1 a high plus must be generated on E when writing to LCD
;
; D4 <----> PK2
; D5 <----> PK3
; D6 <----> PK4
; D7 <----> PK5
; R/W pin on LCD is connected to ground in this board (Write Only connection)
*/
//; initalize the LCD
// check HD44780 datasheet
void LCD_init(){
delay_ms(15); //wait 15ms (datasheet)
DDRK = 0xFF; // config port K as an output port.
//send 3 as a nibble first time (datasheet)
lcd_send_nibble(3);
delay_us(4100); //wait 4.1 ms (datasheet)
//send 3 as a nibble second time (datasheet)
lcd_send_nibble(3);
delay_us(100); //wait 100us (datasheet)
//send 3 as a nibble 3rd time (datasheet)
lcd_send_nibble(3);
//send 2 as a nibble 4th time (datasheet)
lcd_send_nibble(2);
//start configuration now
// function set: 0 0 1 DL N F x x
// ;(DL= 0 for 4 bit mode, N=1 for 2lines, F=0 for 5x7)
lcd_send_cmd(0x28); // LCD is connected as 4-bit mode interface to port K
// display Off: 0 0 0 0 1 D C B
// D = 0 C =0 B = 0
lcd_send_cmd(0x08);
LCD_clear();
//display On: 0 0 0 0 1 D C B
//D = 1 C =0 B = 0
//display on, cursor off, no blinking
lcd_send_cmd(0x0C);
//entry mode: 0 0 0 0 0 1 I/D S
// I/D = 1 cursor increment, S = 0 to disable display shift
lcd_send_cmd(0x06);
}
//send lower nibble [3:0] out to LCD
void lcd_send_nibble(char c){
c &= 0x0F;
c <<= 2; // adjust for portk[5:2]
//drive port K pins and generate a 1us pulse on E
PORTK = c; //E = 0, RS = 0 PORTK[5:2] = data[5:2]
PORTK |= E; //E = 1 , RS =0
PORTK &= ~E; //E = 0 , RS =0
delay_us(40); //wait 40us (datasheet)
}
// send 8-bit command to LCD
void lcd_send_cmd(unsigned char cmd){
char save = cmd;
//send upper nibble first
cmd &= 0xF0;
cmd >>= 2; // adjust for portk [5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0
PORTK &=~E; // E = 0 , RS =0
delay_us(40);
//send lower nibble next
cmd = save;
cmd &= 0x0F;
cmd <<= 2; // adjust for portk[5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0
PORTK &=~E; // E = 0 , RS =0
delay_us(40);
}
// send 8-bit data to LCD
// same as lcd_send_cmd except RS must be 1
void lcd_send_data(unsigned char data){
char save = data;
//send upper nibble first
data &=0xF0;
data >>= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1
PORTK &=~E; // E = 0 , RS =1
delay_us(40);
//send lower nibble next
data = save;
data &=0x0F;
data <<= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1
PORTK &=~E; // E = 0 , RS =1
delay_us(40);
}
//put the cursor at row and col. LCD with 2x16
//row: 0 or 1
//col: 0 through 15
void LCD_setCursor(int row, int col){
static char A[]={0,0x40};
row &=1;
col &=0x0F;
lcd_send_cmd((A[row]|0x80) + col);
}
//Clear the LCD and send cursor home
void LCD_clear(){
//$01 Clear command (datasheet)
lcd_send_cmd(0x01);
//wait 1.6ms (datasheet)
delay_us(1600);
//$02 Cursor Home command (datasheet)
lcd_send_cmd(0x02);
//wait 1.6ms (datasheet)
delay_us(1600);
}
// print a character on LCD at the current cursor pos
void LCD_putchar(char ch){
lcd_send_data(ch);
}
//print a string on LCD
void LCD_print(char *s){
while(*s)
LCD_putchar(*s++);
}
Explanation / Answer
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include"Keypad.h"
#include "LCD.h"
#define EDIT_COL 810
char buf[8];
int bufp;
void just_demo(void);
void delay_ms(unsigned);
void main(void) {
char k;
int i;
Keypad_init();
LCD_init();
LCD_setCursor(0,0);
LCD_print("Enter Pos:");
LCD_setCursor(1,0);
LCD_print("Curr Pos:");
LCD_setCursor(1,EDIT_COL);
LCD_print("Stop."); // assume stopped & at pos = 0
for(;;) {
//read the command position from user...
//first put the cursor there so that we print as user is entering keys...
LCD_setCursor(0,EDIT_COL);
//next: keep reading until user press '#' which is key E in this board
//store in buffer & display on LCD what user is entering
//we will assume correct entry
bufp = 0;
k = Keypad_wait_keypress();
while( k!= 0x0E && bufp < 8 ){
buf[bufp++] = k; // store pressed key in buffer
LCD_putchar(k+'0'); //display as user is entering
Keypad_wait_keyup(); //wait until user release this key
k = Keypad_wait_keypress(); //read next key and back to check...
}
//your code should begin here...
//buf has the commanded position and bufp is their count
//move the stepper to that angle given its current position.....
just_demo();
//The stepper should have reached its commanded pos now....
//display curr pos
LCD_setCursor(1,EDIT_COL);
for(i = 0;i < bufp ; i++)
LCD_putchar(buf[i]+'0');
//erase old commanded pos
LCD_setCursor(0,EDIT_COL);
LCD_print(" ");
}
}
void just_demo(){
int i;
for( i = 0; i < 5 ; i++){
LCD_setCursor(1, EDIT_COL);
LCD_print("Mot...");
delay_ms(500);
LCD_setCursor(1, EDIT_COL);
LCD_print(" ");
delay_ms(500);
}
}
/*----------------------------------
;
; delay for 1 us
*/
void delay_1us(){
asm{
PSHX
LDX #4
L1: DBNE X,L1
PULX
}
}
/*------------------------------------------------
; delay_us
------------------------------------------------*/
void delay_us(unsigned int us ){
asm{
pshd
dd: JSR delay_1us
DBNE D, dd
puld
}
}
/*-------------------
; delay_ms
;----------------------------- */
void delay_ms(unsigned int ms){
asm{
pshd
; 2 clock cycles
PSHX ; 2 clock cycles
OutLoop:
LDX #7993 ; 2
InLoop:
DBNE X, InLoop ; 3/3 ( 3 cycles both ways)
DBNE D, OutLoop ; 3/3
PULX ; 3
puld
}
}
[Keypad.C]
#include "keypad.h"
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
void delay_us(unsigned int);
void delay_ms(unsigned int);
// Keypad Device Driver
int col, row;
/*-------------------------------------------------------------
; Keypad_init
; The Keypad on the dragon12 board is connected to port A
; configure port A pins as input & enable the internal pullup registers on them
void LCD_init(){
delay_ms(15); //wait 15ms (datasheet)
DDRK = 0xFF; // config port K as an output port.
//send 3 as a nibble first time (datasheet)
lcd_send_nibble(3);
delay_us(4100); //wait 4.1 ms (datasheet)
//send 3 as a nibble second time (datasheet)
lcd_send_nibble(3);
delay_us(100); //wait 100us (datasheet)
//send 3 as a nibble 3rd time (datasheet)
lcd_send_nibble(3);
//send 2 as a nibble 4th time (datasheet)
lcd_send_nibble(2);
//start configuration now
// function set: 0 0 1 DL N F x x
// ;(DL= 0 for 4 bit mode, N=1 for 2lines, F=0 for 5x7)
lcd_send_cmd(0x28); // LCD is connected as 4-bit mode interface to port K
// display Off: 0 0 0 0 1 D C B
// D = 0 C =0 B = 0
lcd_send_cmd(0x08);
LCD_clear();
//display On: 0 0 0 0 1 D C B
//D = 1 C =0 B = 0
//display on, cursor off, no blinking
lcd_send_cmd(0x0C);
//entry mode: 0 0 0 0 0 1 I/D S
// I/D = 1 cursor increment, S = 0 to disable display shift
lcd_send_cmd(0x06);
}
//send lower nibble [3:0] out to LCD
void lcd_send_nibble(char c){
c &= 0x0F;
c <<= 2; // adjust for portk[5:2]
//drive port K pins and generate a 1us pulse on E
PORTK = c; //E = 0, RS = 0 PORTK[5:2] = data[5:2]
PORTK |= E; //E = 1 , RS =0
PORTK &= ~E; //E = 0 , RS =0
delay_us(40); //wait 40us (datasheet)
}
// send 8-bit command to LCD
void lcd_send_cmd(unsigned char cmd){
char save = cmd;
//send upper nibble first
cmd &= 0xF0;
cmd >>= 2; // adjust for portk [5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0
PORTK &=~E; // E = 0 , RS =0
delay_us(40);
//send lower nibble next
cmd = save;
cmd &= 0x0F;
cmd <<= 2; // adjust for portk[5:2]
PORTK = cmd; // E = 0, RS = 0 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =0
PORTK &=~E; // E = 0 , RS =0
delay_us(40);
}
// send 8-bit data to LCD
// same as lcd_send_cmd except RS must be 1
void lcd_send_data(unsigned char data){
char save = data;
//send upper nibble first
data &=0xF0;
data >>= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1
PORTK &=~E; // E = 0 , RS =1
delay_us(40);
//send lower nibble next
data = save;
data &=0x0F;
data <<= 2;
data |= RS;
PORTK = data; // E = 0 , RS = 1 PORTK[5:2] = data[5:2]
//generate a pulse on E
PORTK |=E; // E = 1 , RS =1
PORTK &=~E; // E = 0 , RS =1
delay_us(40);
}
//put the cursor at row and col. LCD with 2x16
//row: 0 or 1
//col: 0 through 15
void LCD_setCursor(int row, int col){
static char A[]={0,0x40};
row &=1;
col &=0x0F;
lcd_send_cmd((A[row]|0x80) + col);
}